Cosmic Ray Report

Date time: 29/06/2026 05:50:53

Total jobs: 1234

Complete: 1234 (100.00%)

Surviving mutants: 321 (26.01%)

operator: core/ReplaceBinaryOperator_Add_Sub, occurrence: 0, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -71,7 +71,7 @@
             return False
 
         expected_signature = (
-            "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
+            "sha256=" - hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
         )
 
         try:
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f11ef462250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f11ef6c2270>
payload = b'{"test": "data"}', signature = 'sha256=invalid'

    def verify_signature(self, payload: bytes, signature: str) -> bool:
        """Verify GitHub webhook signature.
    
        Args:
            payload: Request payload
            signature: X-Hub-Signature-256 header value
    
        Returns:
            True if signature is valid
        """
        if not signature:
            return False
    
        expected_signature = (
>           "sha256=" - hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
        )
E       TypeError: unsupported operand type(s) for -: 'str' and 'str'

stampbot/webhook_handler.py:74: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - TypeError: unsupported operand type(s) for -: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.69s
operator: core/ReplaceBinaryOperator_Add_Sub, occurrence: 1, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -596,7 +596,7 @@
                     "message": "Help message posted" if success else "Failed to post help message",
                 }
 
-            if command in repo_config.approve_commands + repo_config.unapprove_commands:
+            if command in repo_config.approve_commands - repo_config.unapprove_commands:
                 has_permission = await run_in_threadpool(
                     github_client.user_has_permission,
                     installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fdc3a61c2d0>
mock_github_client = <MagicMock name='github_client' id='140583780458448'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fdc3a61c2d0>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
            pr_number = int(pr_url.split("/")[-1])
        elif "pull_request" in payload:
            pr_number = payload["pull_request"]["number"]
        else:
            return {"status": "error", "message": "Not a PR comment"}
    
        repo = payload.get("repository", {})
        repo_full_name = repo.get("full_name")
        repo_default_branch = repo.get("default_branch") or "main"
        repo_owner = repo.get("owner", {})
        owner_login = repo_owner.get("login")
        owner_type = repo_owner.get("type")
        installation_id = payload.get("installation", {}).get("id")
        commenter = comment.get("user", {}).get("login", "unknown")
    
        with create_span(
            "webhook.handle_chatops",
            {
                "github.repo": repo_full_name or "unknown",
                "github.pr_number": pr_number,
                "chatops.commenter": commenter,
            },
        ) as span:
            if not all([pr_number, repo_full_name, installation_id]):
                logger.warning("Missing required fields in comment event")
                add_span_attributes(span, {"chatops.result": "missing_fields"})
                set_span_ok(span)
                return {"status": "error", "message": "Missing required fields"}
    
            # Get repository configuration
            repo_config = await self._get_repo_config(
                installation_id,
                repo_full_name,
                repo_default_branch,
                owner_login,
                owner_type,
            )
    
            if repo_config.config_error:
                add_span_attributes(
                    span,
                    {
                        "chatops.result": "config_error",
                        "chatops.config_error": repo_config.config_error,
                    },
                )
                set_span_ok(span)
                return {
                    "status": "error",
                    "message": "Invalid repository configuration",
                }
    
            if not repo_config.chatops_enabled:
                add_span_attributes(span, {"chatops.result": "disabled"})
                set_span_ok(span)
                return {"status": "ignored", "message": "Chatops not enabled"}
    
            # Parse command
            command_match = re.search(r"@stampbot\s+(\w+)", comment_body)
            if not command_match:
                chatops_commands_total.labels(command="none", status="ignored").inc()
                add_span_attributes(span, {"chatops.result": "no_command"})
                set_span_ok(span)
                return {"status": "ignored", "message": "No command found"}
    
            command = command_match.group(1).lower()
            add_span_attributes(span, {"chatops.command": command})
    
            if command == "help":
                success = await self._post_help(
                    installation_id,
                    repo_full_name,
                    pr_number,
                    repo_config,
                )
    
                chatops_commands_total.labels(
                    command="help",
                    status="success" if success else "failure",
                ).inc()
    
                add_span_attributes(
                    span, {"chatops.result": "help_posted" if success else "help_failed"}
                )
                set_span_ok(span)
    
                return {
                    "status": "success" if success else "error",
                    "message": "Help message posted" if success else "Failed to post help message",
                }
    
>           if command in repo_config.approve_commands - repo_config.unapprove_commands:
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for -: 'BoxList' and 'BoxList'

stampbot/webhook_handler.py:599: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:05:22.704210Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:05:22.704807Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:05:22.704210Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:05:22.704807Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - TypeError: unsupported operand type(s) for -: 'BoxList' and 'BoxList'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.79s
operator: core/ReplaceBinaryOperator_Add_Sub, occurrence: 2, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -853,7 +853,7 @@
         if repo_config.required_labels:
             filters.append(
                 "required labels: "
-                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
+                - ", ".join(f"`{label}`" for label in repo_config.required_labels)
             )
         if repo_config.required_title_patterns:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f8038355fd0>
mock_github_client = <MagicMock name='github_client' id='140188675736640'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f8038355fd0>
repo_config = <stampbot.config.RepoConfig object at 0x7f80384ed020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
>               "required labels: "
                - ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
E           TypeError: unsupported operand type(s) for -: 'str' and 'str'

stampbot/webhook_handler.py:855: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:04:15.478183Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:04:15.478183Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for -: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.81s
operator: core/ReplaceBinaryOperator_Add_Sub, occurrence: 3, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -858,7 +858,7 @@
         if repo_config.required_title_patterns:
             filters.append(
                 "required title patterns: "
-                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
+                - ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
             )
         if repo_config.allowed_users:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f2657a665d0>
mock_github_client = <MagicMock name='github_client' id='139802656179264'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f2657a665d0>
repo_config = <stampbot.config.RepoConfig object at 0x7f2657bad020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
>               "required title patterns: "
                - ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
E           TypeError: unsupported operand type(s) for -: 'str' and 'str'

stampbot/webhook_handler.py:860: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:34:11.398054Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:34:11.398054Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for -: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.83s
operator: core/ReplaceBinaryOperator_Add_Sub, occurrence: 4, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -862,7 +862,7 @@
             )
         if repo_config.allowed_users:
             filters.append(
-                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
+                "allowed users: " - ", ".join(f"`{user}`" for user in repo_config.allowed_users)
             )
         if repo_config.allowed_teams:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fb445e82090>
mock_github_client = <MagicMock name='github_client' id='140412243854400'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fb445e82090>
repo_config = <stampbot.config.RepoConfig object at 0x7fb445e95020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
>               "allowed users: " - ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
E           TypeError: unsupported operand type(s) for -: 'str' and 'str'

stampbot/webhook_handler.py:865: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:09:01.635703Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:09:01.635703Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for -: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.82s
operator: core/ReplaceBinaryOperator_Add_Sub, occurrence: 5, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -866,7 +866,7 @@
             )
         if repo_config.allowed_teams:
             filters.append(
-                "allowed teams: " + ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
+                "allowed teams: " - ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
             )
 
         if filters:
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f0e89b8e4b0>
mock_github_client = <MagicMock name='github_client' id='139700417037376'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f0e89b8e4b0>
repo_config = <stampbot.config.RepoConfig object at 0x7f0e89b9d020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
        if repo_config.allowed_teams:
            filters.append(
>               "allowed teams: " - ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
            )
E           TypeError: unsupported operand type(s) for -: 'str' and 'str'

stampbot/webhook_handler.py:869: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:07:10.718440Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:07:10.718440Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for -: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.82s
operator: core/ReplaceBinaryOperator_Add_Mul, occurrence: 0, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -71,7 +71,7 @@
             return False
 
         expected_signature = (
-            "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
+            "sha256=" * hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
         )
 
         try:
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f369435a250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f36945ba270>
payload = b'{"test": "data"}', signature = 'sha256=invalid'

    def verify_signature(self, payload: bytes, signature: str) -> bool:
        """Verify GitHub webhook signature.
    
        Args:
            payload: Request payload
            signature: X-Hub-Signature-256 header value
    
        Returns:
            True if signature is valid
        """
        if not signature:
            return False
    
        expected_signature = (
>           "sha256=" * hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
        )
E       TypeError: can't multiply sequence by non-int of type 'str'

stampbot/webhook_handler.py:74: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - TypeError: can't multiply sequence by non-int of type 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.68s
operator: core/ReplaceBinaryOperator_Add_Mul, occurrence: 1, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -596,7 +596,7 @@
                     "message": "Help message posted" if success else "Failed to post help message",
                 }
 
-            if command in repo_config.approve_commands + repo_config.unapprove_commands:
+            if command in repo_config.approve_commands * repo_config.unapprove_commands:
                 has_permission = await run_in_threadpool(
                     github_client.user_has_permission,
                     installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f35d2985d50>
mock_github_client = <MagicMock name='github_client' id='139869144489936'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f35d2985d50>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
            pr_number = int(pr_url.split("/")[-1])
        elif "pull_request" in payload:
            pr_number = payload["pull_request"]["number"]
        else:
            return {"status": "error", "message": "Not a PR comment"}
    
        repo = payload.get("repository", {})
        repo_full_name = repo.get("full_name")
        repo_default_branch = repo.get("default_branch") or "main"
        repo_owner = repo.get("owner", {})
        owner_login = repo_owner.get("login")
        owner_type = repo_owner.get("type")
        installation_id = payload.get("installation", {}).get("id")
        commenter = comment.get("user", {}).get("login", "unknown")
    
        with create_span(
            "webhook.handle_chatops",
            {
                "github.repo": repo_full_name or "unknown",
                "github.pr_number": pr_number,
                "chatops.commenter": commenter,
            },
        ) as span:
            if not all([pr_number, repo_full_name, installation_id]):
                logger.warning("Missing required fields in comment event")
                add_span_attributes(span, {"chatops.result": "missing_fields"})
                set_span_ok(span)
                return {"status": "error", "message": "Missing required fields"}
    
            # Get repository configuration
            repo_config = await self._get_repo_config(
                installation_id,
                repo_full_name,
                repo_default_branch,
                owner_login,
                owner_type,
            )
    
            if repo_config.config_error:
                add_span_attributes(
                    span,
                    {
                        "chatops.result": "config_error",
                        "chatops.config_error": repo_config.config_error,
                    },
                )
                set_span_ok(span)
                return {
                    "status": "error",
                    "message": "Invalid repository configuration",
                }
    
            if not repo_config.chatops_enabled:
                add_span_attributes(span, {"chatops.result": "disabled"})
                set_span_ok(span)
                return {"status": "ignored", "message": "Chatops not enabled"}
    
            # Parse command
            command_match = re.search(r"@stampbot\s+(\w+)", comment_body)
            if not command_match:
                chatops_commands_total.labels(command="none", status="ignored").inc()
                add_span_attributes(span, {"chatops.result": "no_command"})
                set_span_ok(span)
                return {"status": "ignored", "message": "No command found"}
    
            command = command_match.group(1).lower()
            add_span_attributes(span, {"chatops.command": command})
    
            if command == "help":
                success = await self._post_help(
                    installation_id,
                    repo_full_name,
                    pr_number,
                    repo_config,
                )
    
                chatops_commands_total.labels(
                    command="help",
                    status="success" if success else "failure",
                ).inc()
    
                add_span_attributes(
                    span, {"chatops.result": "help_posted" if success else "help_failed"}
                )
                set_span_ok(span)
    
                return {
                    "status": "success" if success else "error",
                    "message": "Help message posted" if success else "Failed to post help message",
                }
    
>           if command in repo_config.approve_commands * repo_config.unapprove_commands:
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: can't multiply sequence by non-int of type 'BoxList'

stampbot/webhook_handler.py:599: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:33:09.956337Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:33:09.956934Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:33:09.956337Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:33:09.956934Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - TypeError: can't multiply sequence by non-int of type 'BoxList'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.77s
operator: core/ReplaceBinaryOperator_Add_Mul, occurrence: 2, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -853,7 +853,7 @@
         if repo_config.required_labels:
             filters.append(
                 "required labels: "
-                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
+                * ", ".join(f"`{label}`" for label in repo_config.required_labels)
             )
         if repo_config.required_title_patterns:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f403a956030>
mock_github_client = <MagicMock name='github_client' id='139913837675584'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f403a956030>
repo_config = <stampbot.config.RepoConfig object at 0x7f403aaed020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
>               "required labels: "
                * ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
E           TypeError: can't multiply sequence by non-int of type 'str'

stampbot/webhook_handler.py:855: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:17:58.352560Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:17:58.352560Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: can't multiply sequence by non-int of type 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.80s
operator: core/ReplaceBinaryOperator_Add_Mul, occurrence: 3, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -858,7 +858,7 @@
         if repo_config.required_title_patterns:
             filters.append(
                 "required title patterns: "
-                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
+                * ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
             )
         if repo_config.allowed_users:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f121ba97dd0>
mock_github_client = <MagicMock name='github_client' id='139715750331456'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f121ba97dd0>
repo_config = <stampbot.config.RepoConfig object at 0x7f121ba99020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
>               "required title patterns: "
                * ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
E           TypeError: can't multiply sequence by non-int of type 'str'

stampbot/webhook_handler.py:860: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:27:36.565009Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:27:36.565009Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: can't multiply sequence by non-int of type 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.80s
operator: core/ReplaceBinaryOperator_Add_Mul, occurrence: 4, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -862,7 +862,7 @@
             )
         if repo_config.allowed_users:
             filters.append(
-                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
+                "allowed users: " * ", ".join(f"`{user}`" for user in repo_config.allowed_users)
             )
         if repo_config.allowed_teams:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fbd8da82030>
mock_github_client = <MagicMock name='github_client' id='140452102325312'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fbd8da82030>
repo_config = <stampbot.config.RepoConfig object at 0x7fbd8da95020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
>               "allowed users: " * ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
E           TypeError: can't multiply sequence by non-int of type 'str'

stampbot/webhook_handler.py:865: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:17:08.366670Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:17:08.366670Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: can't multiply sequence by non-int of type 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.81s
operator: core/ReplaceBinaryOperator_Add_Mul, occurrence: 5, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -866,7 +866,7 @@
             )
         if repo_config.allowed_teams:
             filters.append(
-                "allowed teams: " + ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
+                "allowed teams: " * ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
             )
 
         if filters:
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fa6b7d72090>
mock_github_client = <MagicMock name='github_client' id='140354025800768'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fa6b7d72090>
repo_config = <stampbot.config.RepoConfig object at 0x7fa6b7db9020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
        if repo_config.allowed_teams:
            filters.append(
>               "allowed teams: " * ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
            )
E           TypeError: can't multiply sequence by non-int of type 'str'

stampbot/webhook_handler.py:869: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:12:41.286844Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:12:41.286844Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: can't multiply sequence by non-int of type 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.83s
operator: core/ReplaceBinaryOperator_Add_Div, occurrence: 0, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -71,7 +71,7 @@
             return False
 
         expected_signature = (
-            "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
+            "sha256=" / hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
         )
 
         try:
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7fa2f1382250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fa2f15e2270>
payload = b'{"test": "data"}', signature = 'sha256=invalid'

    def verify_signature(self, payload: bytes, signature: str) -> bool:
        """Verify GitHub webhook signature.
    
        Args:
            payload: Request payload
            signature: X-Hub-Signature-256 header value
    
        Returns:
            True if signature is valid
        """
        if not signature:
            return False
    
        expected_signature = (
>           "sha256=" / hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
        )
E       TypeError: unsupported operand type(s) for /: 'str' and 'str'

stampbot/webhook_handler.py:74: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - TypeError: unsupported operand type(s) for /: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceBinaryOperator_Add_Div, occurrence: 1, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -596,7 +596,7 @@
                     "message": "Help message posted" if success else "Failed to post help message",
                 }
 
-            if command in repo_config.approve_commands + repo_config.unapprove_commands:
+            if command in repo_config.approve_commands / repo_config.unapprove_commands:
                 has_permission = await run_in_threadpool(
                     github_client.user_has_permission,
                     installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f682c2e2dd0>
mock_github_client = <MagicMock name='github_client' id='140085395431376'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f682c2e2dd0>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
            pr_number = int(pr_url.split("/")[-1])
        elif "pull_request" in payload:
            pr_number = payload["pull_request"]["number"]
        else:
            return {"status": "error", "message": "Not a PR comment"}
    
        repo = payload.get("repository", {})
        repo_full_name = repo.get("full_name")
        repo_default_branch = repo.get("default_branch") or "main"
        repo_owner = repo.get("owner", {})
        owner_login = repo_owner.get("login")
        owner_type = repo_owner.get("type")
        installation_id = payload.get("installation", {}).get("id")
        commenter = comment.get("user", {}).get("login", "unknown")
    
        with create_span(
            "webhook.handle_chatops",
            {
                "github.repo": repo_full_name or "unknown",
                "github.pr_number": pr_number,
                "chatops.commenter": commenter,
            },
        ) as span:
            if not all([pr_number, repo_full_name, installation_id]):
                logger.warning("Missing required fields in comment event")
                add_span_attributes(span, {"chatops.result": "missing_fields"})
                set_span_ok(span)
                return {"status": "error", "message": "Missing required fields"}
    
            # Get repository configuration
            repo_config = await self._get_repo_config(
                installation_id,
                repo_full_name,
                repo_default_branch,
                owner_login,
                owner_type,
            )
    
            if repo_config.config_error:
                add_span_attributes(
                    span,
                    {
                        "chatops.result": "config_error",
                        "chatops.config_error": repo_config.config_error,
                    },
                )
                set_span_ok(span)
                return {
                    "status": "error",
                    "message": "Invalid repository configuration",
                }
    
            if not repo_config.chatops_enabled:
                add_span_attributes(span, {"chatops.result": "disabled"})
                set_span_ok(span)
                return {"status": "ignored", "message": "Chatops not enabled"}
    
            # Parse command
            command_match = re.search(r"@stampbot\s+(\w+)", comment_body)
            if not command_match:
                chatops_commands_total.labels(command="none", status="ignored").inc()
                add_span_attributes(span, {"chatops.result": "no_command"})
                set_span_ok(span)
                return {"status": "ignored", "message": "No command found"}
    
            command = command_match.group(1).lower()
            add_span_attributes(span, {"chatops.command": command})
    
            if command == "help":
                success = await self._post_help(
                    installation_id,
                    repo_full_name,
                    pr_number,
                    repo_config,
                )
    
                chatops_commands_total.labels(
                    command="help",
                    status="success" if success else "failure",
                ).inc()
    
                add_span_attributes(
                    span, {"chatops.result": "help_posted" if success else "help_failed"}
                )
                set_span_ok(span)
    
                return {
                    "status": "success" if success else "error",
                    "message": "Help message posted" if success else "Failed to post help message",
                }
    
>           if command in repo_config.approve_commands / repo_config.unapprove_commands:
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for /: 'BoxList' and 'BoxList'

stampbot/webhook_handler.py:599: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:44:23.637811Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:44:23.638391Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:44:23.637811Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:44:23.638391Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - TypeError: unsupported operand type(s) for /: 'BoxList' and 'BoxList'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.79s
operator: core/ReplaceBinaryOperator_Add_Div, occurrence: 2, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -853,7 +853,7 @@
         if repo_config.required_labels:
             filters.append(
                 "required labels: "
-                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
+                / ", ".join(f"`{label}`" for label in repo_config.required_labels)
             )
         if repo_config.required_title_patterns:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fcb54882030>
mock_github_client = <MagicMock name='github_client' id='140511273468992'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fcb54882030>
repo_config = <stampbot.config.RepoConfig object at 0x7fcb54895020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
>               "required labels: "
                / ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
E           TypeError: unsupported operand type(s) for /: 'str' and 'str'

stampbot/webhook_handler.py:855: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:48:01.926744Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:48:01.926744Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for /: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.82s
operator: core/ReplaceBinaryOperator_Add_Div, occurrence: 3, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -858,7 +858,7 @@
         if repo_config.required_title_patterns:
             filters.append(
                 "required title patterns: "
-                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
+                / ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
             )
         if repo_config.allowed_users:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f4717956030>
mock_github_client = <MagicMock name='github_client' id='139943315244096'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f4717956030>
repo_config = <stampbot.config.RepoConfig object at 0x7f4717aed020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
>               "required title patterns: "
                / ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
E           TypeError: unsupported operand type(s) for /: 'str' and 'str'

stampbot/webhook_handler.py:860: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:43:30.478216Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:43:30.478216Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for /: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.80s
operator: core/ReplaceBinaryOperator_Add_Div, occurrence: 4, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -862,7 +862,7 @@
             )
         if repo_config.allowed_users:
             filters.append(
-                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
+                "allowed users: " / ", ".join(f"`{user}`" for user in repo_config.allowed_users)
             )
         if repo_config.allowed_teams:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fe00a75e510>
mock_github_client = <MagicMock name='github_client' id='140600225072192'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fe00a75e510>
repo_config = <stampbot.config.RepoConfig object at 0x7fe00a8ed020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
>               "allowed users: " / ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
E           TypeError: unsupported operand type(s) for /: 'str' and 'str'

stampbot/webhook_handler.py:865: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:27:32.658315Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:27:32.658315Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for /: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.82s
operator: core/ReplaceBinaryOperator_Add_Div, occurrence: 5, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -866,7 +866,7 @@
             )
         if repo_config.allowed_teams:
             filters.append(
-                "allowed teams: " + ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
+                "allowed teams: " / ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
             )
 
         if filters:
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f4da3c82090>
mock_github_client = <MagicMock name='github_client' id='139971437184064'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f4da3c82090>
repo_config = <stampbot.config.RepoConfig object at 0x7f4da3c95020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
        if repo_config.allowed_teams:
            filters.append(
>               "allowed teams: " / ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
            )
E           TypeError: unsupported operand type(s) for /: 'str' and 'str'

stampbot/webhook_handler.py:869: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:03:11.036257Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:03:11.036257Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for /: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.85s
operator: core/ReplaceBinaryOperator_Add_FloorDiv, occurrence: 0, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -71,7 +71,7 @@
             return False
 
         expected_signature = (
-            "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
+            "sha256=" // hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
         )
 
         try:
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7fe050d7a250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fe050fd6270>
payload = b'{"test": "data"}', signature = 'sha256=invalid'

    def verify_signature(self, payload: bytes, signature: str) -> bool:
        """Verify GitHub webhook signature.
    
        Args:
            payload: Request payload
            signature: X-Hub-Signature-256 header value
    
        Returns:
            True if signature is valid
        """
        if not signature:
            return False
    
        expected_signature = (
>           "sha256=" // hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
        )
E       TypeError: unsupported operand type(s) for //: 'str' and 'str'

stampbot/webhook_handler.py:74: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - TypeError: unsupported operand type(s) for //: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceBinaryOperator_Add_FloorDiv, occurrence: 1, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -596,7 +596,7 @@
                     "message": "Help message posted" if success else "Failed to post help message",
                 }
 
-            if command in repo_config.approve_commands + repo_config.unapprove_commands:
+            if command in repo_config.approve_commands // repo_config.unapprove_commands:
                 has_permission = await run_in_threadpool(
                     github_client.user_has_permission,
                     installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f418bf579d0>
mock_github_client = <MagicMock name='github_client' id='139919569608656'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f418bf579d0>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
            pr_number = int(pr_url.split("/")[-1])
        elif "pull_request" in payload:
            pr_number = payload["pull_request"]["number"]
        else:
            return {"status": "error", "message": "Not a PR comment"}
    
        repo = payload.get("repository", {})
        repo_full_name = repo.get("full_name")
        repo_default_branch = repo.get("default_branch") or "main"
        repo_owner = repo.get("owner", {})
        owner_login = repo_owner.get("login")
        owner_type = repo_owner.get("type")
        installation_id = payload.get("installation", {}).get("id")
        commenter = comment.get("user", {}).get("login", "unknown")
    
        with create_span(
            "webhook.handle_chatops",
            {
                "github.repo": repo_full_name or "unknown",
                "github.pr_number": pr_number,
                "chatops.commenter": commenter,
            },
        ) as span:
            if not all([pr_number, repo_full_name, installation_id]):
                logger.warning("Missing required fields in comment event")
                add_span_attributes(span, {"chatops.result": "missing_fields"})
                set_span_ok(span)
                return {"status": "error", "message": "Missing required fields"}
    
            # Get repository configuration
            repo_config = await self._get_repo_config(
                installation_id,
                repo_full_name,
                repo_default_branch,
                owner_login,
                owner_type,
            )
    
            if repo_config.config_error:
                add_span_attributes(
                    span,
                    {
                        "chatops.result": "config_error",
                        "chatops.config_error": repo_config.config_error,
                    },
                )
                set_span_ok(span)
                return {
                    "status": "error",
                    "message": "Invalid repository configuration",
                }
    
            if not repo_config.chatops_enabled:
                add_span_attributes(span, {"chatops.result": "disabled"})
                set_span_ok(span)
                return {"status": "ignored", "message": "Chatops not enabled"}
    
            # Parse command
            command_match = re.search(r"@stampbot\s+(\w+)", comment_body)
            if not command_match:
                chatops_commands_total.labels(command="none", status="ignored").inc()
                add_span_attributes(span, {"chatops.result": "no_command"})
                set_span_ok(span)
                return {"status": "ignored", "message": "No command found"}
    
            command = command_match.group(1).lower()
            add_span_attributes(span, {"chatops.command": command})
    
            if command == "help":
                success = await self._post_help(
                    installation_id,
                    repo_full_name,
                    pr_number,
                    repo_config,
                )
    
                chatops_commands_total.labels(
                    command="help",
                    status="success" if success else "failure",
                ).inc()
    
                add_span_attributes(
                    span, {"chatops.result": "help_posted" if success else "help_failed"}
                )
                set_span_ok(span)
    
                return {
                    "status": "success" if success else "error",
                    "message": "Help message posted" if success else "Failed to post help message",
                }
    
>           if command in repo_config.approve_commands // repo_config.unapprove_commands:
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for //: 'BoxList' and 'BoxList'

stampbot/webhook_handler.py:599: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:13:16.886988Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:13:16.887594Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:13:16.886988Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:13:16.887594Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - TypeError: unsupported operand type(s) for //: 'BoxList' and 'BoxList'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.76s
operator: core/ReplaceBinaryOperator_Add_FloorDiv, occurrence: 2, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -853,7 +853,7 @@
         if repo_config.required_labels:
             filters.append(
                 "required labels: "
-                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
+                // ", ".join(f"`{label}`" for label in repo_config.required_labels)
             )
         if repo_config.required_title_patterns:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f36d5a66030>
mock_github_client = <MagicMock name='github_client' id='139873489585216'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f36d5a66030>
repo_config = <stampbot.config.RepoConfig object at 0x7f36d5bc1020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
>               "required labels: "
                // ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
E           TypeError: unsupported operand type(s) for //: 'str' and 'str'

stampbot/webhook_handler.py:855: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:43:17.835526Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:43:17.835526Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for //: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.80s
operator: core/ReplaceBinaryOperator_Add_FloorDiv, occurrence: 3, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -858,7 +858,7 @@
         if repo_config.required_title_patterns:
             filters.append(
                 "required title patterns: "
-                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
+                // ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
             )
         if repo_config.allowed_users:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f5ec0f47350>
mock_github_client = <MagicMock name='github_client' id='140044937151552'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f5ec0f47350>
repo_config = <stampbot.config.RepoConfig object at 0x7f5ec0b99020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
>               "required title patterns: "
                // ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
E           TypeError: unsupported operand type(s) for //: 'str' and 'str'

stampbot/webhook_handler.py:860: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:50:14.153190Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:50:14.153190Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for //: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.80s
operator: core/ReplaceBinaryOperator_Add_FloorDiv, occurrence: 4, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -862,7 +862,7 @@
             )
         if repo_config.allowed_users:
             filters.append(
-                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
+                "allowed users: " // ", ".join(f"`{user}`" for user in repo_config.allowed_users)
             )
         if repo_config.allowed_teams:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f238a586630>
mock_github_client = <MagicMock name='github_client' id='139790621803584'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f238a586630>
repo_config = <stampbot.config.RepoConfig object at 0x7f238a599020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
>               "allowed users: " // ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
E           TypeError: unsupported operand type(s) for //: 'str' and 'str'

stampbot/webhook_handler.py:865: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:48:50.787934Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:48:50.787934Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for //: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.82s
operator: core/ReplaceBinaryOperator_Add_FloorDiv, occurrence: 5, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -866,7 +866,7 @@
             )
         if repo_config.allowed_teams:
             filters.append(
-                "allowed teams: " + ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
+                "allowed teams: " // ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
             )
 
         if filters:
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f73334860f0>
mock_github_client = <MagicMock name='github_client' id='140132758520896'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f73334860f0>
repo_config = <stampbot.config.RepoConfig object at 0x7f7333499020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
        if repo_config.allowed_teams:
            filters.append(
>               "allowed teams: " // ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
            )
E           TypeError: unsupported operand type(s) for //: 'str' and 'str'

stampbot/webhook_handler.py:869: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:14:29.013450Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:14:29.013450Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for //: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.82s
operator: core/ReplaceBinaryOperator_Add_Mod, occurrence: 0, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -71,7 +71,7 @@
             return False
 
         expected_signature = (
-            "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
+            "sha256=" % hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
         )
 
         try:
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f506be56250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f50701ba270>
payload = b'{"test": "data"}', signature = 'sha256=invalid'

    def verify_signature(self, payload: bytes, signature: str) -> bool:
        """Verify GitHub webhook signature.
    
        Args:
            payload: Request payload
            signature: X-Hub-Signature-256 header value
    
        Returns:
            True if signature is valid
        """
        if not signature:
            return False
    
        expected_signature = (
>           "sha256=" % hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
        )
E       TypeError: not all arguments converted during string formatting

stampbot/webhook_handler.py:74: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - TypeError: not all arguments converted during string formatting
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceBinaryOperator_Add_Mod, occurrence: 1, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -596,7 +596,7 @@
                     "message": "Help message posted" if success else "Failed to post help message",
                 }
 
-            if command in repo_config.approve_commands + repo_config.unapprove_commands:
+            if command in repo_config.approve_commands % repo_config.unapprove_commands:
                 has_permission = await run_in_threadpool(
                     github_client.user_has_permission,
                     installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f54dad9dd50>
mock_github_client = <MagicMock name='github_client' id='140002427002832'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f54dad9dd50>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
            pr_number = int(pr_url.split("/")[-1])
        elif "pull_request" in payload:
            pr_number = payload["pull_request"]["number"]
        else:
            return {"status": "error", "message": "Not a PR comment"}
    
        repo = payload.get("repository", {})
        repo_full_name = repo.get("full_name")
        repo_default_branch = repo.get("default_branch") or "main"
        repo_owner = repo.get("owner", {})
        owner_login = repo_owner.get("login")
        owner_type = repo_owner.get("type")
        installation_id = payload.get("installation", {}).get("id")
        commenter = comment.get("user", {}).get("login", "unknown")
    
        with create_span(
            "webhook.handle_chatops",
            {
                "github.repo": repo_full_name or "unknown",
                "github.pr_number": pr_number,
                "chatops.commenter": commenter,
            },
        ) as span:
            if not all([pr_number, repo_full_name, installation_id]):
                logger.warning("Missing required fields in comment event")
                add_span_attributes(span, {"chatops.result": "missing_fields"})
                set_span_ok(span)
                return {"status": "error", "message": "Missing required fields"}
    
            # Get repository configuration
            repo_config = await self._get_repo_config(
                installation_id,
                repo_full_name,
                repo_default_branch,
                owner_login,
                owner_type,
            )
    
            if repo_config.config_error:
                add_span_attributes(
                    span,
                    {
                        "chatops.result": "config_error",
                        "chatops.config_error": repo_config.config_error,
                    },
                )
                set_span_ok(span)
                return {
                    "status": "error",
                    "message": "Invalid repository configuration",
                }
    
            if not repo_config.chatops_enabled:
                add_span_attributes(span, {"chatops.result": "disabled"})
                set_span_ok(span)
                return {"status": "ignored", "message": "Chatops not enabled"}
    
            # Parse command
            command_match = re.search(r"@stampbot\s+(\w+)", comment_body)
            if not command_match:
                chatops_commands_total.labels(command="none", status="ignored").inc()
                add_span_attributes(span, {"chatops.result": "no_command"})
                set_span_ok(span)
                return {"status": "ignored", "message": "No command found"}
    
            command = command_match.group(1).lower()
            add_span_attributes(span, {"chatops.command": command})
    
            if command == "help":
                success = await self._post_help(
                    installation_id,
                    repo_full_name,
                    pr_number,
                    repo_config,
                )
    
                chatops_commands_total.labels(
                    command="help",
                    status="success" if success else "failure",
                ).inc()
    
                add_span_attributes(
                    span, {"chatops.result": "help_posted" if success else "help_failed"}
                )
                set_span_ok(span)
    
                return {
                    "status": "success" if success else "error",
                    "message": "Help message posted" if success else "Failed to post help message",
                }
    
>           if command in repo_config.approve_commands % repo_config.unapprove_commands:
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for %: 'BoxList' and 'BoxList'

stampbot/webhook_handler.py:599: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:36:31.326381Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:36:31.326973Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:36:31.326381Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:36:31.326973Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - TypeError: unsupported operand type(s) for %: 'BoxList' and 'BoxList'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.77s
operator: core/ReplaceBinaryOperator_Add_Mod, occurrence: 2, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -853,7 +853,7 @@
         if repo_config.required_labels:
             filters.append(
                 "required labels: "
-                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
+                % ", ".join(f"`{label}`" for label in repo_config.required_labels)
             )
         if repo_config.required_title_patterns:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f1f4ab56030>
mock_github_client = <MagicMock name='github_client' id='139772374287424'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f1f4ab56030>
repo_config = <stampbot.config.RepoConfig object at 0x7f1f4aced020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
>               "required labels: "
                % ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
E           TypeError: not all arguments converted during string formatting

stampbot/webhook_handler.py:855: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:41:17.905784Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:41:17.905784Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: not all arguments converted during string formatting
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.81s
operator: core/ReplaceBinaryOperator_Add_Mod, occurrence: 3, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -858,7 +858,7 @@
         if repo_config.required_title_patterns:
             filters.append(
                 "required title patterns: "
-                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
+                % ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
             )
         if repo_config.allowed_users:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fc06687a090>
mock_github_client = <MagicMock name='github_client' id='140464330785856'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fc06687a090>
repo_config = <stampbot.config.RepoConfig object at 0x7fc06688d020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
>               "required title patterns: "
                % ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
E           TypeError: not all arguments converted during string formatting

stampbot/webhook_handler.py:860: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:30:51.550075Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:30:51.550075Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: not all arguments converted during string formatting
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.83s
operator: core/ReplaceBinaryOperator_Add_Mod, occurrence: 4, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -862,7 +862,7 @@
             )
         if repo_config.allowed_users:
             filters.append(
-                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
+                "allowed users: " % ", ".join(f"`{user}`" for user in repo_config.allowed_users)
             )
         if repo_config.allowed_teams:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fc99fa66030>
mock_github_client = <MagicMock name='github_client' id='140503943808064'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fc99fa66030>
repo_config = <stampbot.config.RepoConfig object at 0x7fc99fbc1020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
>               "allowed users: " % ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
E           TypeError: not all arguments converted during string formatting

stampbot/webhook_handler.py:865: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:41:19.254001Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:41:19.254001Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: not all arguments converted during string formatting
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.79s
operator: core/ReplaceBinaryOperator_Add_Mod, occurrence: 5, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -866,7 +866,7 @@
             )
         if repo_config.allowed_teams:
             filters.append(
-                "allowed teams: " + ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
+                "allowed teams: " % ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
             )
 
         if filters:
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fe80240a090>
mock_github_client = <MagicMock name='github_client' id='140634447103040'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fe80240a090>
repo_config = <stampbot.config.RepoConfig object at 0x7fe80241d020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
        if repo_config.allowed_teams:
            filters.append(
>               "allowed teams: " % ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
            )
E           TypeError: not all arguments converted during string formatting

stampbot/webhook_handler.py:869: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:06:48.411129Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:06:48.411129Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: not all arguments converted during string formatting
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.81s
operator: core/ReplaceBinaryOperator_Add_Pow, occurrence: 0, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -71,7 +71,7 @@
             return False
 
         expected_signature = (
-            "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
+            "sha256=" ** hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
         )
 
         try:
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f385340e250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f3853676270>
payload = b'{"test": "data"}', signature = 'sha256=invalid'

    def verify_signature(self, payload: bytes, signature: str) -> bool:
        """Verify GitHub webhook signature.
    
        Args:
            payload: Request payload
            signature: X-Hub-Signature-256 header value
    
        Returns:
            True if signature is valid
        """
        if not signature:
            return False
    
        expected_signature = (
>           "sha256=" ** hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
        )
E       TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'

stampbot/webhook_handler.py:74: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceBinaryOperator_Add_Pow, occurrence: 1, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -596,7 +596,7 @@
                     "message": "Help message posted" if success else "Failed to post help message",
                 }
 
-            if command in repo_config.approve_commands + repo_config.unapprove_commands:
+            if command in repo_config.approve_commands ** repo_config.unapprove_commands:
                 has_permission = await run_in_threadpool(
                     github_client.user_has_permission,
                     installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f119d5e6a50>
mock_github_client = <MagicMock name='github_client' id='139713632280528'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f119d5e6a50>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
            pr_number = int(pr_url.split("/")[-1])
        elif "pull_request" in payload:
            pr_number = payload["pull_request"]["number"]
        else:
            return {"status": "error", "message": "Not a PR comment"}
    
        repo = payload.get("repository", {})
        repo_full_name = repo.get("full_name")
        repo_default_branch = repo.get("default_branch") or "main"
        repo_owner = repo.get("owner", {})
        owner_login = repo_owner.get("login")
        owner_type = repo_owner.get("type")
        installation_id = payload.get("installation", {}).get("id")
        commenter = comment.get("user", {}).get("login", "unknown")
    
        with create_span(
            "webhook.handle_chatops",
            {
                "github.repo": repo_full_name or "unknown",
                "github.pr_number": pr_number,
                "chatops.commenter": commenter,
            },
        ) as span:
            if not all([pr_number, repo_full_name, installation_id]):
                logger.warning("Missing required fields in comment event")
                add_span_attributes(span, {"chatops.result": "missing_fields"})
                set_span_ok(span)
                return {"status": "error", "message": "Missing required fields"}
    
            # Get repository configuration
            repo_config = await self._get_repo_config(
                installation_id,
                repo_full_name,
                repo_default_branch,
                owner_login,
                owner_type,
            )
    
            if repo_config.config_error:
                add_span_attributes(
                    span,
                    {
                        "chatops.result": "config_error",
                        "chatops.config_error": repo_config.config_error,
                    },
                )
                set_span_ok(span)
                return {
                    "status": "error",
                    "message": "Invalid repository configuration",
                }
    
            if not repo_config.chatops_enabled:
                add_span_attributes(span, {"chatops.result": "disabled"})
                set_span_ok(span)
                return {"status": "ignored", "message": "Chatops not enabled"}
    
            # Parse command
            command_match = re.search(r"@stampbot\s+(\w+)", comment_body)
            if not command_match:
                chatops_commands_total.labels(command="none", status="ignored").inc()
                add_span_attributes(span, {"chatops.result": "no_command"})
                set_span_ok(span)
                return {"status": "ignored", "message": "No command found"}
    
            command = command_match.group(1).lower()
            add_span_attributes(span, {"chatops.command": command})
    
            if command == "help":
                success = await self._post_help(
                    installation_id,
                    repo_full_name,
                    pr_number,
                    repo_config,
                )
    
                chatops_commands_total.labels(
                    command="help",
                    status="success" if success else "failure",
                ).inc()
    
                add_span_attributes(
                    span, {"chatops.result": "help_posted" if success else "help_failed"}
                )
                set_span_ok(span)
    
                return {
                    "status": "success" if success else "error",
                    "message": "Help message posted" if success else "Failed to post help message",
                }
    
>           if command in repo_config.approve_commands ** repo_config.unapprove_commands:
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for ** or pow(): 'BoxList' and 'BoxList'

stampbot/webhook_handler.py:599: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:15:09.606138Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:15:09.606733Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:15:09.606138Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:15:09.606733Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - TypeError: unsupported operand type(s) for ** or pow(): 'BoxList' and 'BoxList'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.77s
operator: core/ReplaceBinaryOperator_Add_Pow, occurrence: 2, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -853,7 +853,7 @@
         if repo_config.required_labels:
             filters.append(
                 "required labels: "
-                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
+                ** ", ".join(f"`{label}`" for label in repo_config.required_labels)
             )
         if repo_config.required_title_patterns:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fa0f95565d0>
mock_github_client = <MagicMock name='github_client' id='140329354789952'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fa0f95565d0>
repo_config = <stampbot.config.RepoConfig object at 0x7fa0f96ed020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
>               "required labels: "
                ** ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
E           TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'

stampbot/webhook_handler.py:855: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:08:52.190650Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:08:52.190650Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.81s
operator: core/ReplaceBinaryOperator_Add_Pow, occurrence: 3, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -858,7 +858,7 @@
         if repo_config.required_title_patterns:
             filters.append(
                 "required title patterns: "
-                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
+                ** ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
             )
         if repo_config.allowed_users:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f020d65dfd0>
mock_github_client = <MagicMock name='github_client' id='139646791615552'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f020d65dfd0>
repo_config = <stampbot.config.RepoConfig object at 0x7f020d7ed020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
>               "required title patterns: "
                ** ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
E           TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'

stampbot/webhook_handler.py:860: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:18:08.042787Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:18:08.042787Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.79s
operator: core/ReplaceBinaryOperator_Add_Pow, occurrence: 4, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -862,7 +862,7 @@
             )
         if repo_config.allowed_users:
             filters.append(
-                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
+                "allowed users: " ** ", ".join(f"`{user}`" for user in repo_config.allowed_users)
             )
         if repo_config.allowed_teams:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f776f08a090>
mock_github_client = <MagicMock name='github_client' id='140150940845120'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f776f08a090>
repo_config = <stampbot.config.RepoConfig object at 0x7f776f099020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
>               "allowed users: " ** ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
E           TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'

stampbot/webhook_handler.py:865: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:25:46.333919Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:25:46.333919Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.81s
operator: core/ReplaceBinaryOperator_Add_Pow, occurrence: 5, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -866,7 +866,7 @@
             )
         if repo_config.allowed_teams:
             filters.append(
-                "allowed teams: " + ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
+                "allowed teams: " ** ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
             )
 
         if filters:
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f9682b82030>
mock_github_client = <MagicMock name='github_client' id='140284415099968'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f9682b82030>
repo_config = <stampbot.config.RepoConfig object at 0x7f9682b95020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
        if repo_config.allowed_teams:
            filters.append(
>               "allowed teams: " ** ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
            )
E           TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'

stampbot/webhook_handler.py:869: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:37:10.842874Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:37:10.842874Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.80s
operator: core/ReplaceBinaryOperator_Add_RShift, occurrence: 0, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -71,7 +71,7 @@
             return False
 
         expected_signature = (
-            "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
+            "sha256=" >> hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
         )
 
         try:
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f9423c8a250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f9423eea270>
payload = b'{"test": "data"}', signature = 'sha256=invalid'

    def verify_signature(self, payload: bytes, signature: str) -> bool:
        """Verify GitHub webhook signature.
    
        Args:
            payload: Request payload
            signature: X-Hub-Signature-256 header value
    
        Returns:
            True if signature is valid
        """
        if not signature:
            return False
    
        expected_signature = (
>           "sha256=" >> hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
        )
E       TypeError: unsupported operand type(s) for >>: 'str' and 'str'

stampbot/webhook_handler.py:74: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - TypeError: unsupported operand type(s) for >>: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.71s
operator: core/ReplaceBinaryOperator_Add_RShift, occurrence: 1, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -596,7 +596,7 @@
                     "message": "Help message posted" if success else "Failed to post help message",
                 }
 
-            if command in repo_config.approve_commands + repo_config.unapprove_commands:
+            if command in repo_config.approve_commands >> repo_config.unapprove_commands:
                 has_permission = await run_in_threadpool(
                     github_client.user_has_permission,
                     installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f332c153bd0>
mock_github_client = <MagicMock name='github_client' id='139857763397856'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f332c153bd0>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
            pr_number = int(pr_url.split("/")[-1])
        elif "pull_request" in payload:
            pr_number = payload["pull_request"]["number"]
        else:
            return {"status": "error", "message": "Not a PR comment"}
    
        repo = payload.get("repository", {})
        repo_full_name = repo.get("full_name")
        repo_default_branch = repo.get("default_branch") or "main"
        repo_owner = repo.get("owner", {})
        owner_login = repo_owner.get("login")
        owner_type = repo_owner.get("type")
        installation_id = payload.get("installation", {}).get("id")
        commenter = comment.get("user", {}).get("login", "unknown")
    
        with create_span(
            "webhook.handle_chatops",
            {
                "github.repo": repo_full_name or "unknown",
                "github.pr_number": pr_number,
                "chatops.commenter": commenter,
            },
        ) as span:
            if not all([pr_number, repo_full_name, installation_id]):
                logger.warning("Missing required fields in comment event")
                add_span_attributes(span, {"chatops.result": "missing_fields"})
                set_span_ok(span)
                return {"status": "error", "message": "Missing required fields"}
    
            # Get repository configuration
            repo_config = await self._get_repo_config(
                installation_id,
                repo_full_name,
                repo_default_branch,
                owner_login,
                owner_type,
            )
    
            if repo_config.config_error:
                add_span_attributes(
                    span,
                    {
                        "chatops.result": "config_error",
                        "chatops.config_error": repo_config.config_error,
                    },
                )
                set_span_ok(span)
                return {
                    "status": "error",
                    "message": "Invalid repository configuration",
                }
    
            if not repo_config.chatops_enabled:
                add_span_attributes(span, {"chatops.result": "disabled"})
                set_span_ok(span)
                return {"status": "ignored", "message": "Chatops not enabled"}
    
            # Parse command
            command_match = re.search(r"@stampbot\s+(\w+)", comment_body)
            if not command_match:
                chatops_commands_total.labels(command="none", status="ignored").inc()
                add_span_attributes(span, {"chatops.result": "no_command"})
                set_span_ok(span)
                return {"status": "ignored", "message": "No command found"}
    
            command = command_match.group(1).lower()
            add_span_attributes(span, {"chatops.command": command})
    
            if command == "help":
                success = await self._post_help(
                    installation_id,
                    repo_full_name,
                    pr_number,
                    repo_config,
                )
    
                chatops_commands_total.labels(
                    command="help",
                    status="success" if success else "failure",
                ).inc()
    
                add_span_attributes(
                    span, {"chatops.result": "help_posted" if success else "help_failed"}
                )
                set_span_ok(span)
    
                return {
                    "status": "success" if success else "error",
                    "message": "Help message posted" if success else "Failed to post help message",
                }
    
>           if command in repo_config.approve_commands >> repo_config.unapprove_commands:
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for >>: 'BoxList' and 'BoxList'

stampbot/webhook_handler.py:599: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:11:12.102253Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:11:12.102813Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:11:12.102253Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:11:12.102813Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - TypeError: unsupported operand type(s) for >>: 'BoxList' and 'BoxList'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.76s
operator: core/ReplaceBinaryOperator_Add_RShift, occurrence: 2, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -853,7 +853,7 @@
         if repo_config.required_labels:
             filters.append(
                 "required labels: "
-                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
+                >> ", ".join(f"`{label}`" for label in repo_config.required_labels)
             )
         if repo_config.required_title_patterns:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fe48158a090>
mock_github_client = <MagicMock name='github_client' id='140619399513152'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fe48158a090>
repo_config = <stampbot.config.RepoConfig object at 0x7fe481599020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
>               "required labels: "
                >> ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
E           TypeError: unsupported operand type(s) for >>: 'str' and 'str'

stampbot/webhook_handler.py:855: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:40:13.877127Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:40:13.877127Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for >>: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.80s
operator: core/ReplaceBinaryOperator_Add_RShift, occurrence: 3, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -858,7 +858,7 @@
         if repo_config.required_title_patterns:
             filters.append(
                 "required title patterns: "
-                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
+                >> ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
             )
         if repo_config.allowed_users:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fdbb9f8e030>
mock_github_client = <MagicMock name='github_client' id='140581694833728'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fdbb9f8e030>
repo_config = <stampbot.config.RepoConfig object at 0x7fdbb9f9d020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
>               "required title patterns: "
                >> ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
E           TypeError: unsupported operand type(s) for >>: 'str' and 'str'

stampbot/webhook_handler.py:860: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:15:04.596497Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:15:04.596497Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for >>: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.83s
operator: core/ReplaceBinaryOperator_Add_RShift, occurrence: 4, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -862,7 +862,7 @@
             )
         if repo_config.allowed_users:
             filters.append(
-                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
+                "allowed users: " >> ", ".join(f"`{user}`" for user in repo_config.allowed_users)
             )
         if repo_config.allowed_teams:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f04a727a5d0>
mock_github_client = <MagicMock name='github_client' id='139657961161792'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f04a727a5d0>
repo_config = <stampbot.config.RepoConfig object at 0x7f04a728d020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
>               "allowed users: " >> ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
E           TypeError: unsupported operand type(s) for >>: 'str' and 'str'

stampbot/webhook_handler.py:865: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:38:58.045094Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:38:58.045094Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for >>: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.81s
operator: core/ReplaceBinaryOperator_Add_RShift, occurrence: 5, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -866,7 +866,7 @@
             )
         if repo_config.allowed_teams:
             filters.append(
-                "allowed teams: " + ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
+                "allowed teams: " >> ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
             )
 
         if filters:
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f493aaa2090>
mock_github_client = <MagicMock name='github_client' id='139952493741120'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f493aaa2090>
repo_config = <stampbot.config.RepoConfig object at 0x7f493aab1020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
        if repo_config.allowed_teams:
            filters.append(
>               "allowed teams: " >> ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
            )
E           TypeError: unsupported operand type(s) for >>: 'str' and 'str'

stampbot/webhook_handler.py:869: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:05:12.779528Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:05:12.779528Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for >>: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.85s
operator: core/ReplaceBinaryOperator_Add_LShift, occurrence: 0, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -71,7 +71,7 @@
             return False
 
         expected_signature = (
-            "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
+            "sha256=" << hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
         )
 
         try:
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f2d63472250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f2d636d2270>
payload = b'{"test": "data"}', signature = 'sha256=invalid'

    def verify_signature(self, payload: bytes, signature: str) -> bool:
        """Verify GitHub webhook signature.
    
        Args:
            payload: Request payload
            signature: X-Hub-Signature-256 header value
    
        Returns:
            True if signature is valid
        """
        if not signature:
            return False
    
        expected_signature = (
>           "sha256=" << hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
        )
E       TypeError: unsupported operand type(s) for <<: 'str' and 'str'

stampbot/webhook_handler.py:74: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - TypeError: unsupported operand type(s) for <<: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.69s
operator: core/ReplaceBinaryOperator_Add_LShift, occurrence: 1, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -596,7 +596,7 @@
                     "message": "Help message posted" if success else "Failed to post help message",
                 }
 
-            if command in repo_config.approve_commands + repo_config.unapprove_commands:
+            if command in repo_config.approve_commands << repo_config.unapprove_commands:
                 has_permission = await run_in_threadpool(
                     github_client.user_has_permission,
                     installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f9528cd0250>
mock_github_client = <MagicMock name='github_client' id='140278542229456'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f9528cd0250>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
            pr_number = int(pr_url.split("/")[-1])
        elif "pull_request" in payload:
            pr_number = payload["pull_request"]["number"]
        else:
            return {"status": "error", "message": "Not a PR comment"}
    
        repo = payload.get("repository", {})
        repo_full_name = repo.get("full_name")
        repo_default_branch = repo.get("default_branch") or "main"
        repo_owner = repo.get("owner", {})
        owner_login = repo_owner.get("login")
        owner_type = repo_owner.get("type")
        installation_id = payload.get("installation", {}).get("id")
        commenter = comment.get("user", {}).get("login", "unknown")
    
        with create_span(
            "webhook.handle_chatops",
            {
                "github.repo": repo_full_name or "unknown",
                "github.pr_number": pr_number,
                "chatops.commenter": commenter,
            },
        ) as span:
            if not all([pr_number, repo_full_name, installation_id]):
                logger.warning("Missing required fields in comment event")
                add_span_attributes(span, {"chatops.result": "missing_fields"})
                set_span_ok(span)
                return {"status": "error", "message": "Missing required fields"}
    
            # Get repository configuration
            repo_config = await self._get_repo_config(
                installation_id,
                repo_full_name,
                repo_default_branch,
                owner_login,
                owner_type,
            )
    
            if repo_config.config_error:
                add_span_attributes(
                    span,
                    {
                        "chatops.result": "config_error",
                        "chatops.config_error": repo_config.config_error,
                    },
                )
                set_span_ok(span)
                return {
                    "status": "error",
                    "message": "Invalid repository configuration",
                }
    
            if not repo_config.chatops_enabled:
                add_span_attributes(span, {"chatops.result": "disabled"})
                set_span_ok(span)
                return {"status": "ignored", "message": "Chatops not enabled"}
    
            # Parse command
            command_match = re.search(r"@stampbot\s+(\w+)", comment_body)
            if not command_match:
                chatops_commands_total.labels(command="none", status="ignored").inc()
                add_span_attributes(span, {"chatops.result": "no_command"})
                set_span_ok(span)
                return {"status": "ignored", "message": "No command found"}
    
            command = command_match.group(1).lower()
            add_span_attributes(span, {"chatops.command": command})
    
            if command == "help":
                success = await self._post_help(
                    installation_id,
                    repo_full_name,
                    pr_number,
                    repo_config,
                )
    
                chatops_commands_total.labels(
                    command="help",
                    status="success" if success else "failure",
                ).inc()
    
                add_span_attributes(
                    span, {"chatops.result": "help_posted" if success else "help_failed"}
                )
                set_span_ok(span)
    
                return {
                    "status": "success" if success else "error",
                    "message": "Help message posted" if success else "Failed to post help message",
                }
    
>           if command in repo_config.approve_commands << repo_config.unapprove_commands:
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for <<: 'BoxList' and 'BoxList'

stampbot/webhook_handler.py:599: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:39:20.036890Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:39:20.037475Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:39:20.036890Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:39:20.037475Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - TypeError: unsupported operand type(s) for <<: 'BoxList' and 'BoxList'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.78s
operator: core/ReplaceBinaryOperator_Add_LShift, occurrence: 2, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -853,7 +853,7 @@
         if repo_config.required_labels:
             filters.append(
                 "required labels: "
-                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
+                << ", ".join(f"`{label}`" for label in repo_config.required_labels)
             )
         if repo_config.required_title_patterns:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fe23078e510>
mock_github_client = <MagicMock name='github_client' id='140609452737600'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fe23078e510>
repo_config = <stampbot.config.RepoConfig object at 0x7fe23079d020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
>               "required labels: "
                << ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
E           TypeError: unsupported operand type(s) for <<: 'str' and 'str'

stampbot/webhook_handler.py:855: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:37:05.739793Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:37:05.739793Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for <<: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.80s
operator: core/ReplaceBinaryOperator_Add_LShift, occurrence: 3, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -858,7 +858,7 @@
         if repo_config.required_title_patterns:
             filters.append(
                 "required title patterns: "
-                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
+                << ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
             )
         if repo_config.allowed_users:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f383688e090>
mock_github_client = <MagicMock name='github_client' id='139879410009152'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f383688e090>
repo_config = <stampbot.config.RepoConfig object at 0x7f383689d020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
>               "required title patterns: "
                << ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
E           TypeError: unsupported operand type(s) for <<: 'str' and 'str'

stampbot/webhook_handler.py:860: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:30:17.817674Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:30:17.817674Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for <<: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.80s
operator: core/ReplaceBinaryOperator_Add_LShift, occurrence: 4, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -862,7 +862,7 @@
             )
         if repo_config.allowed_users:
             filters.append(
-                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
+                "allowed users: " << ", ".join(f"`{user}`" for user in repo_config.allowed_users)
             )
         if repo_config.allowed_teams:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f27c1666090>
mock_github_client = <MagicMock name='github_client' id='139808725337152'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f27c1666090>
repo_config = <stampbot.config.RepoConfig object at 0x7f27c17ad020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
>               "allowed users: " << ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
E           TypeError: unsupported operand type(s) for <<: 'str' and 'str'

stampbot/webhook_handler.py:865: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:39:54.628540Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:39:54.628540Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for <<: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.82s
operator: core/ReplaceBinaryOperator_Add_LShift, occurrence: 5, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -866,7 +866,7 @@
             )
         if repo_config.allowed_teams:
             filters.append(
-                "allowed teams: " + ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
+                "allowed teams: " << ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
             )
 
         if filters:
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fd7c1b8a570>
mock_github_client = <MagicMock name='github_client' id='140564644971584'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fd7c1b8a570>
repo_config = <stampbot.config.RepoConfig object at 0x7fd7c1b99020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
        if repo_config.allowed_teams:
            filters.append(
>               "allowed teams: " << ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
            )
E           TypeError: unsupported operand type(s) for <<: 'str' and 'str'

stampbot/webhook_handler.py:869: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:47:02.612598Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:47:02.612598Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for <<: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.81s
operator: core/ReplaceBinaryOperator_Add_BitOr, occurrence: 0, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -71,7 +71,7 @@
             return False
 
         expected_signature = (
-            "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
+            "sha256=" | hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
         )
 
         try:
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7fa96668a250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fa9668ea270>
payload = b'{"test": "data"}', signature = 'sha256=invalid'

    def verify_signature(self, payload: bytes, signature: str) -> bool:
        """Verify GitHub webhook signature.
    
        Args:
            payload: Request payload
            signature: X-Hub-Signature-256 header value
    
        Returns:
            True if signature is valid
        """
        if not signature:
            return False
    
        expected_signature = (
>           "sha256=" | hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
        )
E       TypeError: unsupported operand type(s) for |: 'str' and 'str'

stampbot/webhook_handler.py:74: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - TypeError: unsupported operand type(s) for |: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceBinaryOperator_Add_BitOr, occurrence: 1, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -596,7 +596,7 @@
                     "message": "Help message posted" if success else "Failed to post help message",
                 }
 
-            if command in repo_config.approve_commands + repo_config.unapprove_commands:
+            if command in repo_config.approve_commands | repo_config.unapprove_commands:
                 has_permission = await run_in_threadpool(
                     github_client.user_has_permission,
                     installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fd94cfbc2d0>
mock_github_client = <MagicMock name='github_client' id='140571278401488'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fd94cfbc2d0>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
            pr_number = int(pr_url.split("/")[-1])
        elif "pull_request" in payload:
            pr_number = payload["pull_request"]["number"]
        else:
            return {"status": "error", "message": "Not a PR comment"}
    
        repo = payload.get("repository", {})
        repo_full_name = repo.get("full_name")
        repo_default_branch = repo.get("default_branch") or "main"
        repo_owner = repo.get("owner", {})
        owner_login = repo_owner.get("login")
        owner_type = repo_owner.get("type")
        installation_id = payload.get("installation", {}).get("id")
        commenter = comment.get("user", {}).get("login", "unknown")
    
        with create_span(
            "webhook.handle_chatops",
            {
                "github.repo": repo_full_name or "unknown",
                "github.pr_number": pr_number,
                "chatops.commenter": commenter,
            },
        ) as span:
            if not all([pr_number, repo_full_name, installation_id]):
                logger.warning("Missing required fields in comment event")
                add_span_attributes(span, {"chatops.result": "missing_fields"})
                set_span_ok(span)
                return {"status": "error", "message": "Missing required fields"}
    
            # Get repository configuration
            repo_config = await self._get_repo_config(
                installation_id,
                repo_full_name,
                repo_default_branch,
                owner_login,
                owner_type,
            )
    
            if repo_config.config_error:
                add_span_attributes(
                    span,
                    {
                        "chatops.result": "config_error",
                        "chatops.config_error": repo_config.config_error,
                    },
                )
                set_span_ok(span)
                return {
                    "status": "error",
                    "message": "Invalid repository configuration",
                }
    
            if not repo_config.chatops_enabled:
                add_span_attributes(span, {"chatops.result": "disabled"})
                set_span_ok(span)
                return {"status": "ignored", "message": "Chatops not enabled"}
    
            # Parse command
            command_match = re.search(r"@stampbot\s+(\w+)", comment_body)
            if not command_match:
                chatops_commands_total.labels(command="none", status="ignored").inc()
                add_span_attributes(span, {"chatops.result": "no_command"})
                set_span_ok(span)
                return {"status": "ignored", "message": "No command found"}
    
            command = command_match.group(1).lower()
            add_span_attributes(span, {"chatops.command": command})
    
            if command == "help":
                success = await self._post_help(
                    installation_id,
                    repo_full_name,
                    pr_number,
                    repo_config,
                )
    
                chatops_commands_total.labels(
                    command="help",
                    status="success" if success else "failure",
                ).inc()
    
                add_span_attributes(
                    span, {"chatops.result": "help_posted" if success else "help_failed"}
                )
                set_span_ok(span)
    
                return {
                    "status": "success" if success else "error",
                    "message": "Help message posted" if success else "Failed to post help message",
                }
    
>           if command in repo_config.approve_commands | repo_config.unapprove_commands:
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for |: 'BoxList' and 'BoxList'

stampbot/webhook_handler.py:599: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:29:14.968402Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:29:14.968970Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:29:14.968402Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:29:14.968970Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - TypeError: unsupported operand type(s) for |: 'BoxList' and 'BoxList'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.76s
operator: core/ReplaceBinaryOperator_Add_BitOr, occurrence: 2, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -853,7 +853,7 @@
         if repo_config.required_labels:
             filters.append(
                 "required labels: "
-                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
+                | ", ".join(f"`{label}`" for label in repo_config.required_labels)
             )
         if repo_config.required_title_patterns:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7ff91a986090>
mock_github_client = <MagicMock name='github_client' id='140707869951040'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7ff91a986090>
repo_config = <stampbot.config.RepoConfig object at 0x7ff91a999020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
>               "required labels: "
                | ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
E           TypeError: unsupported operand type(s) for |: 'str' and 'str'

stampbot/webhook_handler.py:855: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:28:55.392577Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:28:55.392577Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for |: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.78s
operator: core/ReplaceBinaryOperator_Add_BitOr, occurrence: 3, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -858,7 +858,7 @@
         if repo_config.required_title_patterns:
             filters.append(
                 "required title patterns: "
-                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
+                | ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
             )
         if repo_config.allowed_users:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f349488a630>
mock_github_client = <MagicMock name='github_client' id='139863807181888'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f349488a630>
repo_config = <stampbot.config.RepoConfig object at 0x7f3494899020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
>               "required title patterns: "
                | ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
E           TypeError: unsupported operand type(s) for |: 'str' and 'str'

stampbot/webhook_handler.py:860: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:35:45.444637Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:35:45.444637Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for |: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.80s
operator: core/ReplaceBinaryOperator_Add_BitOr, occurrence: 4, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -862,7 +862,7 @@
             )
         if repo_config.allowed_users:
             filters.append(
-                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
+                "allowed users: " | ", ".join(f"`{user}`" for user in repo_config.allowed_users)
             )
         if repo_config.allowed_teams:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f6dc1d8a090>
mock_github_client = <MagicMock name='github_client' id='140109380535360'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f6dc1d8a090>
repo_config = <stampbot.config.RepoConfig object at 0x7f6dc1d99020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
>               "allowed users: " | ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
E           TypeError: unsupported operand type(s) for |: 'str' and 'str'

stampbot/webhook_handler.py:865: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:17:53.308580Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:17:53.308580Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for |: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.80s
operator: core/ReplaceBinaryOperator_Add_BitOr, occurrence: 5, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -866,7 +866,7 @@
             )
         if repo_config.allowed_teams:
             filters.append(
-                "allowed teams: " + ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
+                "allowed teams: " | ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
             )
 
         if filters:
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f3bc4466570>
mock_github_client = <MagicMock name='github_client' id='139894672917568'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f3bc4466570>
repo_config = <stampbot.config.RepoConfig object at 0x7f3bc45c1020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
        if repo_config.allowed_teams:
            filters.append(
>               "allowed teams: " | ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
            )
E           TypeError: unsupported operand type(s) for |: 'str' and 'str'

stampbot/webhook_handler.py:869: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:06:18.218839Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:06:18.218839Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for |: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.82s
operator: core/ReplaceBinaryOperator_Add_BitAnd, occurrence: 0, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -71,7 +71,7 @@
             return False
 
         expected_signature = (
-            "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
+            "sha256=" & hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
         )
 
         try:
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f36c7f8e250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f36cc2ee270>
payload = b'{"test": "data"}', signature = 'sha256=invalid'

    def verify_signature(self, payload: bytes, signature: str) -> bool:
        """Verify GitHub webhook signature.
    
        Args:
            payload: Request payload
            signature: X-Hub-Signature-256 header value
    
        Returns:
            True if signature is valid
        """
        if not signature:
            return False
    
        expected_signature = (
>           "sha256=" & hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
        )
E       TypeError: unsupported operand type(s) for &: 'str' and 'str'

stampbot/webhook_handler.py:74: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - TypeError: unsupported operand type(s) for &: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceBinaryOperator_Add_BitAnd, occurrence: 1, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -596,7 +596,7 @@
                     "message": "Help message posted" if success else "Failed to post help message",
                 }
 
-            if command in repo_config.approve_commands + repo_config.unapprove_commands:
+            if command in repo_config.approve_commands & repo_config.unapprove_commands:
                 has_permission = await run_in_threadpool(
                     github_client.user_has_permission,
                     installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fd10c993dd0>
mock_github_client = <MagicMock name='github_client' id='140535838466000'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fd10c993dd0>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
            pr_number = int(pr_url.split("/")[-1])
        elif "pull_request" in payload:
            pr_number = payload["pull_request"]["number"]
        else:
            return {"status": "error", "message": "Not a PR comment"}
    
        repo = payload.get("repository", {})
        repo_full_name = repo.get("full_name")
        repo_default_branch = repo.get("default_branch") or "main"
        repo_owner = repo.get("owner", {})
        owner_login = repo_owner.get("login")
        owner_type = repo_owner.get("type")
        installation_id = payload.get("installation", {}).get("id")
        commenter = comment.get("user", {}).get("login", "unknown")
    
        with create_span(
            "webhook.handle_chatops",
            {
                "github.repo": repo_full_name or "unknown",
                "github.pr_number": pr_number,
                "chatops.commenter": commenter,
            },
        ) as span:
            if not all([pr_number, repo_full_name, installation_id]):
                logger.warning("Missing required fields in comment event")
                add_span_attributes(span, {"chatops.result": "missing_fields"})
                set_span_ok(span)
                return {"status": "error", "message": "Missing required fields"}
    
            # Get repository configuration
            repo_config = await self._get_repo_config(
                installation_id,
                repo_full_name,
                repo_default_branch,
                owner_login,
                owner_type,
            )
    
            if repo_config.config_error:
                add_span_attributes(
                    span,
                    {
                        "chatops.result": "config_error",
                        "chatops.config_error": repo_config.config_error,
                    },
                )
                set_span_ok(span)
                return {
                    "status": "error",
                    "message": "Invalid repository configuration",
                }
    
            if not repo_config.chatops_enabled:
                add_span_attributes(span, {"chatops.result": "disabled"})
                set_span_ok(span)
                return {"status": "ignored", "message": "Chatops not enabled"}
    
            # Parse command
            command_match = re.search(r"@stampbot\s+(\w+)", comment_body)
            if not command_match:
                chatops_commands_total.labels(command="none", status="ignored").inc()
                add_span_attributes(span, {"chatops.result": "no_command"})
                set_span_ok(span)
                return {"status": "ignored", "message": "No command found"}
    
            command = command_match.group(1).lower()
            add_span_attributes(span, {"chatops.command": command})
    
            if command == "help":
                success = await self._post_help(
                    installation_id,
                    repo_full_name,
                    pr_number,
                    repo_config,
                )
    
                chatops_commands_total.labels(
                    command="help",
                    status="success" if success else "failure",
                ).inc()
    
                add_span_attributes(
                    span, {"chatops.result": "help_posted" if success else "help_failed"}
                )
                set_span_ok(span)
    
                return {
                    "status": "success" if success else "error",
                    "message": "Help message posted" if success else "Failed to post help message",
                }
    
>           if command in repo_config.approve_commands & repo_config.unapprove_commands:
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for &: 'BoxList' and 'BoxList'

stampbot/webhook_handler.py:599: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:59:52.918399Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:59:52.918976Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:59:52.918399Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:59:52.918976Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - TypeError: unsupported operand type(s) for &: 'BoxList' and 'BoxList'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.76s
operator: core/ReplaceBinaryOperator_Add_BitAnd, occurrence: 2, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -853,7 +853,7 @@
         if repo_config.required_labels:
             filters.append(
                 "required labels: "
-                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
+                & ", ".join(f"`{label}`" for label in repo_config.required_labels)
             )
         if repo_config.required_title_patterns:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fc464a8dfd0>
mock_github_client = <MagicMock name='github_client' id='140481479279680'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fc464a8dfd0>
repo_config = <stampbot.config.RepoConfig object at 0x7fc464a9d020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
>               "required labels: "
                & ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
E           TypeError: unsupported operand type(s) for &: 'str' and 'str'

stampbot/webhook_handler.py:855: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:10:51.831495Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:10:51.831495Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for &: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.82s
operator: core/ReplaceBinaryOperator_Add_BitAnd, occurrence: 3, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -858,7 +858,7 @@
         if repo_config.required_title_patterns:
             filters.append(
                 "required title patterns: "
-                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
+                & ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
             )
         if repo_config.allowed_users:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7efed2a82570>
mock_github_client = <MagicMock name='github_client' id='139632921199680'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7efed2a82570>
repo_config = <stampbot.config.RepoConfig object at 0x7efed2a95020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
>               "required title patterns: "
                & ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
E           TypeError: unsupported operand type(s) for &: 'str' and 'str'

stampbot/webhook_handler.py:860: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:37:05.365905Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:37:05.365905Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for &: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.82s
operator: core/ReplaceBinaryOperator_Add_BitAnd, occurrence: 4, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -862,7 +862,7 @@
             )
         if repo_config.allowed_users:
             filters.append(
-                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
+                "allowed users: " & ", ".join(f"`{user}`" for user in repo_config.allowed_users)
             )
         if repo_config.allowed_teams:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fdead689f10>
mock_github_client = <MagicMock name='github_client' id='140594368955456'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fdead689f10>
repo_config = <stampbot.config.RepoConfig object at 0x7fdead699020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
>               "allowed users: " & ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
E           TypeError: unsupported operand type(s) for &: 'str' and 'str'

stampbot/webhook_handler.py:865: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:50:08.422213Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:50:08.422213Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for &: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.81s
operator: core/ReplaceBinaryOperator_Add_BitAnd, occurrence: 5, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -866,7 +866,7 @@
             )
         if repo_config.allowed_teams:
             filters.append(
-                "allowed teams: " + ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
+                "allowed teams: " & ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
             )
 
         if filters:
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f8b30986090>
mock_github_client = <MagicMock name='github_client' id='140235792647232'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f8b30986090>
repo_config = <stampbot.config.RepoConfig object at 0x7f8b30995020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
        if repo_config.allowed_teams:
            filters.append(
>               "allowed teams: " & ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
            )
E           TypeError: unsupported operand type(s) for &: 'str' and 'str'

stampbot/webhook_handler.py:869: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:32:47.958659Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:32:47.958659Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for &: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.80s
operator: core/ReplaceBinaryOperator_Add_BitXor, occurrence: 0, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -71,7 +71,7 @@
             return False
 
         expected_signature = (
-            "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
+            "sha256=" ^ hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
         )
 
         try:
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f58bda82250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f58bdce6270>
payload = b'{"test": "data"}', signature = 'sha256=invalid'

    def verify_signature(self, payload: bytes, signature: str) -> bool:
        """Verify GitHub webhook signature.
    
        Args:
            payload: Request payload
            signature: X-Hub-Signature-256 header value
    
        Returns:
            True if signature is valid
        """
        if not signature:
            return False
    
        expected_signature = (
>           "sha256=" ^ hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
        )
E       TypeError: unsupported operand type(s) for ^: 'str' and 'str'

stampbot/webhook_handler.py:74: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - TypeError: unsupported operand type(s) for ^: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.68s
operator: core/ReplaceBinaryOperator_Add_BitXor, occurrence: 1, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -596,7 +596,7 @@
                     "message": "Help message posted" if success else "Failed to post help message",
                 }
 
-            if command in repo_config.approve_commands + repo_config.unapprove_commands:
+            if command in repo_config.approve_commands ^ repo_config.unapprove_commands:
                 has_permission = await run_in_threadpool(
                     github_client.user_has_permission,
                     installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f8272b8a450>
mock_github_client = <MagicMock name='github_client' id='140198179364816'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f8272b8a450>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
            pr_number = int(pr_url.split("/")[-1])
        elif "pull_request" in payload:
            pr_number = payload["pull_request"]["number"]
        else:
            return {"status": "error", "message": "Not a PR comment"}
    
        repo = payload.get("repository", {})
        repo_full_name = repo.get("full_name")
        repo_default_branch = repo.get("default_branch") or "main"
        repo_owner = repo.get("owner", {})
        owner_login = repo_owner.get("login")
        owner_type = repo_owner.get("type")
        installation_id = payload.get("installation", {}).get("id")
        commenter = comment.get("user", {}).get("login", "unknown")
    
        with create_span(
            "webhook.handle_chatops",
            {
                "github.repo": repo_full_name or "unknown",
                "github.pr_number": pr_number,
                "chatops.commenter": commenter,
            },
        ) as span:
            if not all([pr_number, repo_full_name, installation_id]):
                logger.warning("Missing required fields in comment event")
                add_span_attributes(span, {"chatops.result": "missing_fields"})
                set_span_ok(span)
                return {"status": "error", "message": "Missing required fields"}
    
            # Get repository configuration
            repo_config = await self._get_repo_config(
                installation_id,
                repo_full_name,
                repo_default_branch,
                owner_login,
                owner_type,
            )
    
            if repo_config.config_error:
                add_span_attributes(
                    span,
                    {
                        "chatops.result": "config_error",
                        "chatops.config_error": repo_config.config_error,
                    },
                )
                set_span_ok(span)
                return {
                    "status": "error",
                    "message": "Invalid repository configuration",
                }
    
            if not repo_config.chatops_enabled:
                add_span_attributes(span, {"chatops.result": "disabled"})
                set_span_ok(span)
                return {"status": "ignored", "message": "Chatops not enabled"}
    
            # Parse command
            command_match = re.search(r"@stampbot\s+(\w+)", comment_body)
            if not command_match:
                chatops_commands_total.labels(command="none", status="ignored").inc()
                add_span_attributes(span, {"chatops.result": "no_command"})
                set_span_ok(span)
                return {"status": "ignored", "message": "No command found"}
    
            command = command_match.group(1).lower()
            add_span_attributes(span, {"chatops.command": command})
    
            if command == "help":
                success = await self._post_help(
                    installation_id,
                    repo_full_name,
                    pr_number,
                    repo_config,
                )
    
                chatops_commands_total.labels(
                    command="help",
                    status="success" if success else "failure",
                ).inc()
    
                add_span_attributes(
                    span, {"chatops.result": "help_posted" if success else "help_failed"}
                )
                set_span_ok(span)
    
                return {
                    "status": "success" if success else "error",
                    "message": "Help message posted" if success else "Failed to post help message",
                }
    
>           if command in repo_config.approve_commands ^ repo_config.unapprove_commands:
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for ^: 'BoxList' and 'BoxList'

stampbot/webhook_handler.py:599: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:39:48.420701Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:39:48.421308Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:39:48.420701Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:39:48.421308Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - TypeError: unsupported operand type(s) for ^: 'BoxList' and 'BoxList'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.78s
operator: core/ReplaceBinaryOperator_Add_BitXor, occurrence: 2, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -853,7 +853,7 @@
         if repo_config.required_labels:
             filters.append(
                 "required labels: "
-                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
+                ^ ", ".join(f"`{label}`" for label in repo_config.required_labels)
             )
         if repo_config.required_title_patterns:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f945b65e570>
mock_github_client = <MagicMock name='github_client' id='140275165463616'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f945b65e570>
repo_config = <stampbot.config.RepoConfig object at 0x7f945b7ed020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
>               "required labels: "
                ^ ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
E           TypeError: unsupported operand type(s) for ^: 'str' and 'str'

stampbot/webhook_handler.py:855: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:15:31.992600Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:15:31.992600Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for ^: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.79s
operator: core/ReplaceBinaryOperator_Add_BitXor, occurrence: 3, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -858,7 +858,7 @@
         if repo_config.required_title_patterns:
             filters.append(
                 "required title patterns: "
-                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
+                ^ ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
             )
         if repo_config.allowed_users:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f1e9a85e570>
mock_github_client = <MagicMock name='github_client' id='139769418384448'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f1e9a85e570>
repo_config = <stampbot.config.RepoConfig object at 0x7f1e9a9ed020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
>               "required title patterns: "
                ^ ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
E           TypeError: unsupported operand type(s) for ^: 'str' and 'str'

stampbot/webhook_handler.py:860: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:49:10.438338Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:49:10.438338Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for ^: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.83s
operator: core/ReplaceBinaryOperator_Add_BitXor, occurrence: 4, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -862,7 +862,7 @@
             )
         if repo_config.allowed_users:
             filters.append(
-                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
+                "allowed users: " ^ ", ".join(f"`{user}`" for user in repo_config.allowed_users)
             )
         if repo_config.allowed_teams:
             filters.append(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f0c96c0a090>
mock_github_client = <MagicMock name='github_client' id='139692045714496'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f0c96c0a090>
repo_config = <stampbot.config.RepoConfig object at 0x7f0c96c1d020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
>               "allowed users: " ^ ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
E           TypeError: unsupported operand type(s) for ^: 'str' and 'str'

stampbot/webhook_handler.py:865: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:28:25.520385Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:28:25.520385Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for ^: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.79s
operator: core/ReplaceBinaryOperator_Add_BitXor, occurrence: 5, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -866,7 +866,7 @@
             )
         if repo_config.allowed_teams:
             filters.append(
-                "allowed teams: " + ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
+                "allowed teams: " ^ ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
             )
 
         if filters:
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f485da57e30>
mock_github_client = <MagicMock name='github_client' id='139948785615936'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:499: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:577: in _handle_pr_comment
    success = await self._post_help(
stampbot/webhook_handler.py:901: in _post_help
    self._format_help_message(repo_config),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f485da57e30>
repo_config = <stampbot.config.RepoConfig object at 0x7f485da59020>

    def _format_help_message(self, repo_config: RepoConfig) -> str:
        """Format a help message for the effective repository configuration.
    
        Args:
            repo_config: Repository configuration
    
        Returns:
            Markdown help text.
        """
        lines = ["## Stampbot Help", ""]
    
        lines.extend(
            [
                "### ChatOps Commands",
                "",
                (
                    f"Approve and unapprove commands require "
                    f"**{repo_config.chatops_required_permission}** permission or higher."
                ),
                "",
            ]
        )
    
        approve_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.approve_commands
        )
        unapprove_commands = ", ".join(
            f"`@stampbot {command}`" for command in repo_config.unapprove_commands
        )
        lines.extend(
            [
                f"- **Approve**: {approve_commands}",
                f"- **Unapprove**: {unapprove_commands}",
                "- **Help**: `@stampbot help`",
                "",
                "### Label-Based Auto-Approval",
                "",
            ]
        )
    
        if repo_config.auto_approve_on_label:
            approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
            lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
        else:
            lines.append("Label-based auto-approval is disabled in this repository.")
    
        filters = []
        if repo_config.required_labels:
            filters.append(
                "required labels: "
                + ", ".join(f"`{label}`" for label in repo_config.required_labels)
            )
        if repo_config.required_title_patterns:
            filters.append(
                "required title patterns: "
                + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
            )
        if repo_config.allowed_users:
            filters.append(
                "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
            )
        if repo_config.allowed_teams:
            filters.append(
>               "allowed teams: " ^ ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
            )
E           TypeError: unsupported operand type(s) for ^: 'str' and 'str'

stampbot/webhook_handler.py:869: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:24:25.081796Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:24:25.081796Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - TypeError: unsupported operand type(s) for ^: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.81s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 0, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -988,7 +988,7 @@
                 comment,
             )
 
-            duration = time.time() - start_time
+            duration = time.time() + start_time
             pr_approval_duration_seconds.observe(duration)
 
             status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.27s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 1, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1052,7 +1052,7 @@
                         pr_number,
                         extra={"repo": repo_full_name, "pr_number": pr_number},
                     )
-                    duration = time.time() - start_time
+                    duration = time.time() + start_time
                     pr_dismissal_duration_seconds.observe(duration)
                     pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                     add_span_attributes(span, {"dismissal.result": "no_reviews"})
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 2, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1072,7 +1072,7 @@
                     )
                     success = success and result
 
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 pr_dismissal_duration_seconds.observe(duration)
 
                 status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 3, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1084,7 +1084,7 @@
                 return success
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 pr_dismissal_duration_seconds.observe(duration)
                 pr_dismissals_total.labels(trigger_type=trigger_type, status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 0, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -988,7 +988,7 @@
                 comment,
             )
 
-            duration = time.time() - start_time
+            duration = time.time() * start_time
             pr_approval_duration_seconds.observe(duration)
 
             status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 1, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1052,7 +1052,7 @@
                         pr_number,
                         extra={"repo": repo_full_name, "pr_number": pr_number},
                     )
-                    duration = time.time() - start_time
+                    duration = time.time() * start_time
                     pr_dismissal_duration_seconds.observe(duration)
                     pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                     add_span_attributes(span, {"dismissal.result": "no_reviews"})
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 2, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1072,7 +1072,7 @@
                     )
                     success = success and result
 
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 pr_dismissal_duration_seconds.observe(duration)
 
                 status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 3, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1084,7 +1084,7 @@
                 return success
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 pr_dismissal_duration_seconds.observe(duration)
                 pr_dismissals_total.labels(trigger_type=trigger_type, status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 0, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -988,7 +988,7 @@
                 comment,
             )
 
-            duration = time.time() - start_time
+            duration = time.time() / start_time
             pr_approval_duration_seconds.observe(duration)
 
             status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 1, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1052,7 +1052,7 @@
                         pr_number,
                         extra={"repo": repo_full_name, "pr_number": pr_number},
                     )
-                    duration = time.time() - start_time
+                    duration = time.time() / start_time
                     pr_dismissal_duration_seconds.observe(duration)
                     pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                     add_span_attributes(span, {"dismissal.result": "no_reviews"})
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 2, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1072,7 +1072,7 @@
                     )
                     success = success and result
 
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 pr_dismissal_duration_seconds.observe(duration)
 
                 status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 3, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1084,7 +1084,7 @@
                 return success
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 pr_dismissal_duration_seconds.observe(duration)
                 pr_dismissals_total.labels(trigger_type=trigger_type, status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.21s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 0, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -988,7 +988,7 @@
                 comment,
             )
 
-            duration = time.time() - start_time
+            duration = time.time() // start_time
             pr_approval_duration_seconds.observe(duration)
 
             status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 1, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1052,7 +1052,7 @@
                         pr_number,
                         extra={"repo": repo_full_name, "pr_number": pr_number},
                     )
-                    duration = time.time() - start_time
+                    duration = time.time() // start_time
                     pr_dismissal_duration_seconds.observe(duration)
                     pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                     add_span_attributes(span, {"dismissal.result": "no_reviews"})
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 2, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1072,7 +1072,7 @@
                     )
                     success = success and result
 
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 pr_dismissal_duration_seconds.observe(duration)
 
                 status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 3, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1084,7 +1084,7 @@
                 return success
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 pr_dismissal_duration_seconds.observe(duration)
                 pr_dismissals_total.labels(trigger_type=trigger_type, status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 0, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -988,7 +988,7 @@
                 comment,
             )
 
-            duration = time.time() - start_time
+            duration = time.time() % start_time
             pr_approval_duration_seconds.observe(duration)
 
             status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 1, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1052,7 +1052,7 @@
                         pr_number,
                         extra={"repo": repo_full_name, "pr_number": pr_number},
                     )
-                    duration = time.time() - start_time
+                    duration = time.time() % start_time
                     pr_dismissal_duration_seconds.observe(duration)
                     pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                     add_span_attributes(span, {"dismissal.result": "no_reviews"})
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 2, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1072,7 +1072,7 @@
                     )
                     success = success and result
 
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 pr_dismissal_duration_seconds.observe(duration)
 
                 status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 3, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1084,7 +1084,7 @@
                 return success
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 pr_dismissal_duration_seconds.observe(duration)
                 pr_dismissals_total.labels(trigger_type=trigger_type, status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 0, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -988,7 +988,7 @@
                 comment,
             )
 
-            duration = time.time() - start_time
+            duration = time.time() ** start_time
             pr_approval_duration_seconds.observe(duration)
 
             status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f02c1312ea0>
mock_github_client = <MagicMock name='github_client' id='139649808662944'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
>       result = await webhook_handler.handle_event("pull_request", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:71: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:116: in handle_event
    result = await self._handle_pull_request(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:307: in _handle_pull_request
    success = await self._approve_pr(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f02c1312ea0>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
comment = 'Auto-approved by Stampbot (label: autoapprove)'
trigger_type = 'label', skip_existing_check = False, head_sha = None

    async def _approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str,
        trigger_type: str,
        skip_existing_check: bool = False,
        head_sha: str | None = None,
    ) -> bool:
        """Approve a PR and track metrics.
    
        Checks for existing active approvals first to avoid duplicate comments.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            comment: Approval comment
            trigger_type: What triggered the approval (label, chatops)
            skip_existing_check: Whether to skip duplicate active approval detection
            head_sha: Current PR head SHA, used to distinguish stale approvals
    
        Returns:
            True if successful (or already approved)
        """
        with create_span(
            "webhook.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "approval.trigger_type": trigger_type,
            },
        ) as span:
            if not skip_existing_check:
                if head_sha:
                    existing_reviews = await run_in_threadpool(
                        github_client.find_bot_approval_reviews,
                        installation_id,
                        repo_full_name,
                        pr_number,
                    )
                    existing_approvals = [
                        review["id"]
                        for review in existing_reviews
                        if self._has_current_active_approval([review], head_sha)
                    ]
                else:
                    # Check for existing active approval to avoid duplicates
                    existing_approvals = await run_in_threadpool(
                        github_client.find_bot_reviews,
                        installation_id,
                        repo_full_name,
                        pr_number,
                    )
    
                if existing_approvals:
                    logger.info(
                        "PR #%d in %s already has active approval for current head, skipping",
                        pr_number,
                        repo_full_name,
                        extra={
                            "repo": repo_full_name,
                            "pr_number": pr_number,
                            "existing_review_ids": existing_approvals,
                        },
                    )
                    add_span_attributes(
                        span,
                        {
                            "approval.result": "already_approved",
                            "approval.existing_reviews": len(existing_approvals),
                        },
                    )
                    set_span_ok(span)
                    return True
    
            start_time = time.time()
    
            success = await run_in_threadpool(
                github_client.approve_pr,
                installation_id,
                repo_full_name,
                pr_number,
                comment,
            )
    
>           duration = time.time() ** start_time
                       ^^^^^^^^^^^^^^^^^^^^^^^^^
E           OverflowError: (34, 'Numerical result out of range')

stampbot/webhook_handler.py:991: OverflowError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:44:10.260914Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:44:10.261676Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:44:10.262453Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:44:10.260914Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:44:10.261676Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:44:10.262453Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 1, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1052,7 +1052,7 @@
                         pr_number,
                         extra={"repo": repo_full_name, "pr_number": pr_number},
                     )
-                    duration = time.time() - start_time
+                    duration = time.time() ** start_time
                     pr_dismissal_duration_seconds.observe(duration)
                     pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                     add_span_attributes(span, {"dismissal.result": "no_reviews"})
........................................................................ [ 30%]
........................................................................ [ 60%]
...............................................F
=================================== FAILURES ===================================
_______________________ test_pr_unlabeled_no_bot_reviews _______________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f1ad9d462b0>
mock_github_client = <MagicMock name='github_client' id='139753300858192'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_no_bot_reviews(webhook_handler, mock_github_client):
        """Test removing label when no bot reviews exist."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = []  # No reviews to dismiss
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:291: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:30:05.768837Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:30:05.769410Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:30:05.769844Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T04:30:05.770267Z [info     ] No bot approvals found on PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42}
2026-06-29T04:30:05.770477Z [error    ] Error dismissing approvals: (34, 'Numerical result out of range') [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=error extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "(34, 'Numerical result out of range')"}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:30:05.768837Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:30:05.769410Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:30:05.769844Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:1050 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42}, 'event': 'No bot approvals found on PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:30:05.770267Z'}
ERROR    stampbot.webhook_handler:webhook_handler.py:1091 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "(34, 'Numerical result out of range')"}, 'event': "Error dismissing approvals: (34, 'Numerical result out of range')", 'logger': 'stampbot.webhook_handler', 'level': 'error', 'timestamp': '2026-06-29T04:30:05.770477Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_no_bot_reviews - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 191 passed, 3 deselected, 1 warning in 2.71s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 2, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1072,7 +1072,7 @@
                     )
                     success = success and result
 
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 pr_dismissal_duration_seconds.observe(duration)
 
                 status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f072f085910>
mock_github_client = <MagicMock name='github_client' id='139668829734288'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:264: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:16:57.849027Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:16:57.849623Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:16:57.850054Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T05:16:57.850751Z [error    ] Error dismissing approvals: (34, 'Numerical result out of range') [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=error extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "(34, 'Numerical result out of range')"}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:16:57.849027Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:16:57.849623Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:16:57.850054Z'}
ERROR    stampbot.webhook_handler:webhook_handler.py:1091 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "(34, 'Numerical result out of range')"}, 'event': "Error dismissing approvals: (34, 'Numerical result out of range')", 'logger': 'stampbot.webhook_handler', 'level': 'error', 'timestamp': '2026-06-29T05:16:57.850751Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 3, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1084,7 +1084,7 @@
                 return success
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 pr_dismissal_duration_seconds.observe(duration)
                 pr_dismissals_total.labels(trigger_type=trigger_type, status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
..............F
=================================== FAILURES ===================================
_______________________ test_dismiss_approvals_exception _______________________

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fd4c984c650>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
message = 'Label autoapprove removed', trigger_type = 'label_removed'

    async def _dismiss_approvals(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
        trigger_type: str,
    ) -> bool:
        """Dismiss bot approvals on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            message: Dismissal message
            trigger_type: What triggered the dismissal (label_removed, chatops)
    
        Returns:
            True if successful
        """
        with create_span(
            "webhook.dismiss_approvals",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "dismissal.trigger_type": trigger_type,
            },
        ) as span:
            start_time = time.time()
    
            try:
                # Find all bot reviews
>               review_ids = await run_in_threadpool(
                    github_client.find_bot_reviews,
                    installation_id,
                    repo_full_name,
                    pr_number,
                )

stampbot/webhook_handler.py:1040: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/concurrency.py:34: in run_in_threadpool
    return await anyio.to_thread.run_sync(func)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/to_thread.py:63: in run_sync
    return await get_async_backend().run_sync_in_worker_thread(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:2596: in run_sync_in_worker_thread
    return await future
           ^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:1029: in run
    result = context.run(func, *args)
             ^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_reviews' id='140551889603952'>
args = (12345, 'octocat/hello-world', 42), kwargs = {}
effect = Exception('API error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fd4c984c650>
mock_github_client = <MagicMock name='github_client' id='140551889601936'>

    @pytest.mark.asyncio
    async def test_dismiss_approvals_exception(webhook_handler, mock_github_client):
        """Test _dismiss_approvals handles exceptions gracefully."""
        payload = load_fixture("pr_unlabeled_autoapprove")
    
        # Make find_bot_reviews raise an exception
        mock_github_client.find_bot_reviews.side_effect = Exception("API error")
    
>       result = await webhook_handler.handle_event("pull_request", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:944: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:116: in handle_event
    result = await self._handle_pull_request(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:350: in _handle_pull_request
    success = await self._dismiss_approvals(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fd4c984c650>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
message = 'Label autoapprove removed', trigger_type = 'label_removed'

    async def _dismiss_approvals(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
        trigger_type: str,
    ) -> bool:
        """Dismiss bot approvals on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            message: Dismissal message
            trigger_type: What triggered the dismissal (label_removed, chatops)
    
        Returns:
            True if successful
        """
        with create_span(
            "webhook.dismiss_approvals",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "dismissal.trigger_type": trigger_type,
            },
        ) as span:
            start_time = time.time()
    
            try:
                # Find all bot reviews
                review_ids = await run_in_threadpool(
                    github_client.find_bot_reviews,
                    installation_id,
                    repo_full_name,
                    pr_number,
                )
    
                add_span_attributes(span, {"dismissal.reviews_found": len(review_ids)})
    
                if not review_ids:
                    logger.info(
                        "No bot approvals found on PR #%d",
                        pr_number,
                        extra={"repo": repo_full_name, "pr_number": pr_number},
                    )
                    duration = time.time() - start_time
                    pr_dismissal_duration_seconds.observe(duration)
                    pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                    add_span_attributes(span, {"dismissal.result": "no_reviews"})
                    set_span_ok(span)
                    return True
    
                # Dismiss each review
                success = True
                for review_id in review_ids:
                    result = await run_in_threadpool(
                        github_client.dismiss_approval,
                        installation_id,
                        repo_full_name,
                        pr_number,
                        review_id,
                        message,
                    )
                    success = success and result
    
                duration = time.time() - start_time
                pr_dismissal_duration_seconds.observe(duration)
    
                status = "success" if success else "failure"
                pr_dismissals_total.labels(trigger_type=trigger_type, status=status).inc()
    
                add_span_attributes(span, {"dismissal.result": status})
                set_span_ok(span)
    
                return success
    
            except Exception as e:
>               duration = time.time() ** start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               OverflowError: (34, 'Numerical result out of range')

stampbot/webhook_handler.py:1087: OverflowError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:03:50.022269Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:03:50.022815Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:03:50.023266Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:03:50.022269Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:03:50.022815Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:03:50.023266Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_dismiss_approvals_exception - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 230 passed, 3 deselected, 1 warning in 3.44s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 0, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -988,7 +988,7 @@
                 comment,
             )
 
-            duration = time.time() - start_time
+            duration = time.time() >> start_time
             pr_approval_duration_seconds.observe(duration)
 
             status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7ff30cb12ea0>
mock_github_client = <MagicMock name='github_client' id='140681867493792'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
>       result = await webhook_handler.handle_event("pull_request", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:71: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:116: in handle_event
    result = await self._handle_pull_request(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:307: in _handle_pull_request
    success = await self._approve_pr(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7ff30cb12ea0>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
comment = 'Auto-approved by Stampbot (label: autoapprove)'
trigger_type = 'label', skip_existing_check = False, head_sha = None

    async def _approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str,
        trigger_type: str,
        skip_existing_check: bool = False,
        head_sha: str | None = None,
    ) -> bool:
        """Approve a PR and track metrics.
    
        Checks for existing active approvals first to avoid duplicate comments.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            comment: Approval comment
            trigger_type: What triggered the approval (label, chatops)
            skip_existing_check: Whether to skip duplicate active approval detection
            head_sha: Current PR head SHA, used to distinguish stale approvals
    
        Returns:
            True if successful (or already approved)
        """
        with create_span(
            "webhook.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "approval.trigger_type": trigger_type,
            },
        ) as span:
            if not skip_existing_check:
                if head_sha:
                    existing_reviews = await run_in_threadpool(
                        github_client.find_bot_approval_reviews,
                        installation_id,
                        repo_full_name,
                        pr_number,
                    )
                    existing_approvals = [
                        review["id"]
                        for review in existing_reviews
                        if self._has_current_active_approval([review], head_sha)
                    ]
                else:
                    # Check for existing active approval to avoid duplicates
                    existing_approvals = await run_in_threadpool(
                        github_client.find_bot_reviews,
                        installation_id,
                        repo_full_name,
                        pr_number,
                    )
    
                if existing_approvals:
                    logger.info(
                        "PR #%d in %s already has active approval for current head, skipping",
                        pr_number,
                        repo_full_name,
                        extra={
                            "repo": repo_full_name,
                            "pr_number": pr_number,
                            "existing_review_ids": existing_approvals,
                        },
                    )
                    add_span_attributes(
                        span,
                        {
                            "approval.result": "already_approved",
                            "approval.existing_reviews": len(existing_approvals),
                        },
                    )
                    set_span_ok(span)
                    return True
    
            start_time = time.time()
    
            success = await run_in_threadpool(
                github_client.approve_pr,
                installation_id,
                repo_full_name,
                pr_number,
                comment,
            )
    
>           duration = time.time() >> start_time
                       ^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/webhook_handler.py:991: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:00:59.814745Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:00:59.815488Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:00:59.816260Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:00:59.814745Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:00:59.815488Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:00:59.816260Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.72s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 1, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1052,7 +1052,7 @@
                         pr_number,
                         extra={"repo": repo_full_name, "pr_number": pr_number},
                     )
-                    duration = time.time() - start_time
+                    duration = time.time() >> start_time
                     pr_dismissal_duration_seconds.observe(duration)
                     pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                     add_span_attributes(span, {"dismissal.result": "no_reviews"})
........................................................................ [ 30%]
........................................................................ [ 60%]
...............................................F
=================================== FAILURES ===================================
_______________________ test_pr_unlabeled_no_bot_reviews _______________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f031d91a2b0>
mock_github_client = <MagicMock name='github_client' id='139651358119248'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_no_bot_reviews(webhook_handler, mock_github_client):
        """Test removing label when no bot reviews exist."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = []  # No reviews to dismiss
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:291: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:18:04.377724Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:18:04.378298Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:18:04.378733Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T05:18:04.379149Z [info     ] No bot approvals found on PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42}
2026-06-29T05:18:04.379384Z [error    ] Error dismissing approvals: unsupported operand type(s) for >>: 'float' and 'float' [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=error extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for >>: 'float' and 'float'"}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:18:04.377724Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:18:04.378298Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:18:04.378733Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:1050 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42}, 'event': 'No bot approvals found on PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:18:04.379149Z'}
ERROR    stampbot.webhook_handler:webhook_handler.py:1091 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for >>: 'float' and 'float'"}, 'event': "Error dismissing approvals: unsupported operand type(s) for >>: 'float' and 'float'", 'logger': 'stampbot.webhook_handler', 'level': 'error', 'timestamp': '2026-06-29T05:18:04.379384Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_no_bot_reviews - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 191 passed, 3 deselected, 1 warning in 2.69s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 2, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1072,7 +1072,7 @@
                     )
                     success = success and result
 
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 pr_dismissal_duration_seconds.observe(duration)
 
                 status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f0378e7d910>
mock_github_client = <MagicMock name='github_client' id='139652889249168'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:264: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:40:22.784710Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:40:22.785279Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:40:22.785706Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T05:40:22.786371Z [error    ] Error dismissing approvals: unsupported operand type(s) for >>: 'float' and 'float' [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=error extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for >>: 'float' and 'float'"}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:40:22.784710Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:40:22.785279Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:40:22.785706Z'}
ERROR    stampbot.webhook_handler:webhook_handler.py:1091 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for >>: 'float' and 'float'"}, 'event': "Error dismissing approvals: unsupported operand type(s) for >>: 'float' and 'float'", 'logger': 'stampbot.webhook_handler', 'level': 'error', 'timestamp': '2026-06-29T05:40:22.786371Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 3, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1084,7 +1084,7 @@
                 return success
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 pr_dismissal_duration_seconds.observe(duration)
                 pr_dismissals_total.labels(trigger_type=trigger_type, status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
..............F
=================================== FAILURES ===================================
_______________________ test_dismiss_approvals_exception _______________________

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fab5c64c650>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
message = 'Label autoapprove removed', trigger_type = 'label_removed'

    async def _dismiss_approvals(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
        trigger_type: str,
    ) -> bool:
        """Dismiss bot approvals on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            message: Dismissal message
            trigger_type: What triggered the dismissal (label_removed, chatops)
    
        Returns:
            True if successful
        """
        with create_span(
            "webhook.dismiss_approvals",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "dismissal.trigger_type": trigger_type,
            },
        ) as span:
            start_time = time.time()
    
            try:
                # Find all bot reviews
>               review_ids = await run_in_threadpool(
                    github_client.find_bot_reviews,
                    installation_id,
                    repo_full_name,
                    pr_number,
                )

stampbot/webhook_handler.py:1040: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/concurrency.py:34: in run_in_threadpool
    return await anyio.to_thread.run_sync(func)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/to_thread.py:63: in run_sync
    return await get_async_backend().run_sync_in_worker_thread(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:2596: in run_sync_in_worker_thread
    return await future
           ^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:1029: in run
    result = context.run(func, *args)
             ^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_reviews' id='140373965131120'>
args = (12345, 'octocat/hello-world', 42), kwargs = {}
effect = Exception('API error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fab5c64c650>
mock_github_client = <MagicMock name='github_client' id='140373965129104'>

    @pytest.mark.asyncio
    async def test_dismiss_approvals_exception(webhook_handler, mock_github_client):
        """Test _dismiss_approvals handles exceptions gracefully."""
        payload = load_fixture("pr_unlabeled_autoapprove")
    
        # Make find_bot_reviews raise an exception
        mock_github_client.find_bot_reviews.side_effect = Exception("API error")
    
>       result = await webhook_handler.handle_event("pull_request", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:944: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:116: in handle_event
    result = await self._handle_pull_request(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:350: in _handle_pull_request
    success = await self._dismiss_approvals(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fab5c64c650>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
message = 'Label autoapprove removed', trigger_type = 'label_removed'

    async def _dismiss_approvals(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
        trigger_type: str,
    ) -> bool:
        """Dismiss bot approvals on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            message: Dismissal message
            trigger_type: What triggered the dismissal (label_removed, chatops)
    
        Returns:
            True if successful
        """
        with create_span(
            "webhook.dismiss_approvals",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "dismissal.trigger_type": trigger_type,
            },
        ) as span:
            start_time = time.time()
    
            try:
                # Find all bot reviews
                review_ids = await run_in_threadpool(
                    github_client.find_bot_reviews,
                    installation_id,
                    repo_full_name,
                    pr_number,
                )
    
                add_span_attributes(span, {"dismissal.reviews_found": len(review_ids)})
    
                if not review_ids:
                    logger.info(
                        "No bot approvals found on PR #%d",
                        pr_number,
                        extra={"repo": repo_full_name, "pr_number": pr_number},
                    )
                    duration = time.time() - start_time
                    pr_dismissal_duration_seconds.observe(duration)
                    pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                    add_span_attributes(span, {"dismissal.result": "no_reviews"})
                    set_span_ok(span)
                    return True
    
                # Dismiss each review
                success = True
                for review_id in review_ids:
                    result = await run_in_threadpool(
                        github_client.dismiss_approval,
                        installation_id,
                        repo_full_name,
                        pr_number,
                        review_id,
                        message,
                    )
                    success = success and result
    
                duration = time.time() - start_time
                pr_dismissal_duration_seconds.observe(duration)
    
                status = "success" if success else "failure"
                pr_dismissals_total.labels(trigger_type=trigger_type, status=status).inc()
    
                add_span_attributes(span, {"dismissal.result": status})
                set_span_ok(span)
    
                return success
    
            except Exception as e:
>               duration = time.time() >> start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/webhook_handler.py:1087: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:46:52.789827Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:46:52.790390Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:46:52.790835Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:46:52.789827Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:46:52.790390Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:46:52.790835Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_dismiss_approvals_exception - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 230 passed, 3 deselected, 1 warning in 3.44s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 0, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -988,7 +988,7 @@
                 comment,
             )
 
-            duration = time.time() - start_time
+            duration = time.time() << start_time
             pr_approval_duration_seconds.observe(duration)
 
             status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f5856a0aea0>
mock_github_client = <MagicMock name='github_client' id='140017387995552'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
>       result = await webhook_handler.handle_event("pull_request", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:71: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:116: in handle_event
    result = await self._handle_pull_request(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:307: in _handle_pull_request
    success = await self._approve_pr(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f5856a0aea0>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
comment = 'Auto-approved by Stampbot (label: autoapprove)'
trigger_type = 'label', skip_existing_check = False, head_sha = None

    async def _approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str,
        trigger_type: str,
        skip_existing_check: bool = False,
        head_sha: str | None = None,
    ) -> bool:
        """Approve a PR and track metrics.
    
        Checks for existing active approvals first to avoid duplicate comments.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            comment: Approval comment
            trigger_type: What triggered the approval (label, chatops)
            skip_existing_check: Whether to skip duplicate active approval detection
            head_sha: Current PR head SHA, used to distinguish stale approvals
    
        Returns:
            True if successful (or already approved)
        """
        with create_span(
            "webhook.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "approval.trigger_type": trigger_type,
            },
        ) as span:
            if not skip_existing_check:
                if head_sha:
                    existing_reviews = await run_in_threadpool(
                        github_client.find_bot_approval_reviews,
                        installation_id,
                        repo_full_name,
                        pr_number,
                    )
                    existing_approvals = [
                        review["id"]
                        for review in existing_reviews
                        if self._has_current_active_approval([review], head_sha)
                    ]
                else:
                    # Check for existing active approval to avoid duplicates
                    existing_approvals = await run_in_threadpool(
                        github_client.find_bot_reviews,
                        installation_id,
                        repo_full_name,
                        pr_number,
                    )
    
                if existing_approvals:
                    logger.info(
                        "PR #%d in %s already has active approval for current head, skipping",
                        pr_number,
                        repo_full_name,
                        extra={
                            "repo": repo_full_name,
                            "pr_number": pr_number,
                            "existing_review_ids": existing_approvals,
                        },
                    )
                    add_span_attributes(
                        span,
                        {
                            "approval.result": "already_approved",
                            "approval.existing_reviews": len(existing_approvals),
                        },
                    )
                    set_span_ok(span)
                    return True
    
            start_time = time.time()
    
            success = await run_in_threadpool(
                github_client.approve_pr,
                installation_id,
                repo_full_name,
                pr_number,
                comment,
            )
    
>           duration = time.time() << start_time
                       ^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/webhook_handler.py:991: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:48:16.190257Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:48:16.190973Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:48:16.191745Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:48:16.190257Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:48:16.190973Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:48:16.191745Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.69s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 1, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1052,7 +1052,7 @@
                         pr_number,
                         extra={"repo": repo_full_name, "pr_number": pr_number},
                     )
-                    duration = time.time() - start_time
+                    duration = time.time() << start_time
                     pr_dismissal_duration_seconds.observe(duration)
                     pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                     add_span_attributes(span, {"dismissal.result": "no_reviews"})
........................................................................ [ 30%]
........................................................................ [ 60%]
...............................................F
=================================== FAILURES ===================================
_______________________ test_pr_unlabeled_no_bot_reviews _______________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f8f13f2e2b0>
mock_github_client = <MagicMock name='github_client' id='140252492141904'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_no_bot_reviews(webhook_handler, mock_github_client):
        """Test removing label when no bot reviews exist."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = []  # No reviews to dismiss
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:291: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:40:58.596656Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:40:58.597294Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:40:58.597731Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T04:40:58.598163Z [info     ] No bot approvals found on PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42}
2026-06-29T04:40:58.598399Z [error    ] Error dismissing approvals: unsupported operand type(s) for <<: 'float' and 'float' [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=error extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for <<: 'float' and 'float'"}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:40:58.596656Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:40:58.597294Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:40:58.597731Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:1050 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42}, 'event': 'No bot approvals found on PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:40:58.598163Z'}
ERROR    stampbot.webhook_handler:webhook_handler.py:1091 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for <<: 'float' and 'float'"}, 'event': "Error dismissing approvals: unsupported operand type(s) for <<: 'float' and 'float'", 'logger': 'stampbot.webhook_handler', 'level': 'error', 'timestamp': '2026-06-29T04:40:58.598399Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_no_bot_reviews - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 191 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 2, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1072,7 +1072,7 @@
                     )
                     success = success and result
 
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 pr_dismissal_duration_seconds.observe(duration)
 
                 status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f1c68179910>
mock_github_client = <MagicMock name='github_client' id='139759913190800'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:264: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:56:23.410181Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:56:23.410773Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:56:23.411201Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T04:56:23.411899Z [error    ] Error dismissing approvals: unsupported operand type(s) for <<: 'float' and 'float' [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=error extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for <<: 'float' and 'float'"}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:56:23.410181Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:56:23.410773Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:56:23.411201Z'}
ERROR    stampbot.webhook_handler:webhook_handler.py:1091 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for <<: 'float' and 'float'"}, 'event': "Error dismissing approvals: unsupported operand type(s) for <<: 'float' and 'float'", 'logger': 'stampbot.webhook_handler', 'level': 'error', 'timestamp': '2026-06-29T04:56:23.411899Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.73s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 3, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1084,7 +1084,7 @@
                 return success
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 pr_dismissal_duration_seconds.observe(duration)
                 pr_dismissals_total.labels(trigger_type=trigger_type, status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
..............F
=================================== FAILURES ===================================
_______________________ test_dismiss_approvals_exception _______________________

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f73710e4350>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
message = 'Label autoapprove removed', trigger_type = 'label_removed'

    async def _dismiss_approvals(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
        trigger_type: str,
    ) -> bool:
        """Dismiss bot approvals on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            message: Dismissal message
            trigger_type: What triggered the dismissal (label_removed, chatops)
    
        Returns:
            True if successful
        """
        with create_span(
            "webhook.dismiss_approvals",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "dismissal.trigger_type": trigger_type,
            },
        ) as span:
            start_time = time.time()
    
            try:
                # Find all bot reviews
>               review_ids = await run_in_threadpool(
                    github_client.find_bot_reviews,
                    installation_id,
                    repo_full_name,
                    pr_number,
                )

stampbot/webhook_handler.py:1040: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/concurrency.py:34: in run_in_threadpool
    return await anyio.to_thread.run_sync(func)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/to_thread.py:63: in run_sync
    return await get_async_backend().run_sync_in_worker_thread(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:2596: in run_sync_in_worker_thread
    return await future
           ^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:1029: in run
    result = context.run(func, *args)
             ^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_reviews' id='140133792943472'>
args = (12345, 'octocat/hello-world', 42), kwargs = {}
effect = Exception('API error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f73710e4350>
mock_github_client = <MagicMock name='github_client' id='140133792941456'>

    @pytest.mark.asyncio
    async def test_dismiss_approvals_exception(webhook_handler, mock_github_client):
        """Test _dismiss_approvals handles exceptions gracefully."""
        payload = load_fixture("pr_unlabeled_autoapprove")
    
        # Make find_bot_reviews raise an exception
        mock_github_client.find_bot_reviews.side_effect = Exception("API error")
    
>       result = await webhook_handler.handle_event("pull_request", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:944: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:116: in handle_event
    result = await self._handle_pull_request(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:350: in _handle_pull_request
    success = await self._dismiss_approvals(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f73710e4350>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
message = 'Label autoapprove removed', trigger_type = 'label_removed'

    async def _dismiss_approvals(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
        trigger_type: str,
    ) -> bool:
        """Dismiss bot approvals on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            message: Dismissal message
            trigger_type: What triggered the dismissal (label_removed, chatops)
    
        Returns:
            True if successful
        """
        with create_span(
            "webhook.dismiss_approvals",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "dismissal.trigger_type": trigger_type,
            },
        ) as span:
            start_time = time.time()
    
            try:
                # Find all bot reviews
                review_ids = await run_in_threadpool(
                    github_client.find_bot_reviews,
                    installation_id,
                    repo_full_name,
                    pr_number,
                )
    
                add_span_attributes(span, {"dismissal.reviews_found": len(review_ids)})
    
                if not review_ids:
                    logger.info(
                        "No bot approvals found on PR #%d",
                        pr_number,
                        extra={"repo": repo_full_name, "pr_number": pr_number},
                    )
                    duration = time.time() - start_time
                    pr_dismissal_duration_seconds.observe(duration)
                    pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                    add_span_attributes(span, {"dismissal.result": "no_reviews"})
                    set_span_ok(span)
                    return True
    
                # Dismiss each review
                success = True
                for review_id in review_ids:
                    result = await run_in_threadpool(
                        github_client.dismiss_approval,
                        installation_id,
                        repo_full_name,
                        pr_number,
                        review_id,
                        message,
                    )
                    success = success and result
    
                duration = time.time() - start_time
                pr_dismissal_duration_seconds.observe(duration)
    
                status = "success" if success else "failure"
                pr_dismissals_total.labels(trigger_type=trigger_type, status=status).inc()
    
                add_span_attributes(span, {"dismissal.result": status})
                set_span_ok(span)
    
                return success
    
            except Exception as e:
>               duration = time.time() << start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/webhook_handler.py:1087: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:45:41.423280Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:45:41.423827Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:45:41.424279Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:45:41.423280Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:45:41.423827Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:45:41.424279Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_dismiss_approvals_exception - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 230 passed, 3 deselected, 1 warning in 3.43s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 0, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -988,7 +988,7 @@
                 comment,
             )
 
-            duration = time.time() - start_time
+            duration = time.time() | start_time
             pr_approval_duration_seconds.observe(duration)
 
             status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f41afa06ea0>
mock_github_client = <MagicMock name='github_client' id='139920096903584'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
>       result = await webhook_handler.handle_event("pull_request", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:71: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:116: in handle_event
    result = await self._handle_pull_request(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:307: in _handle_pull_request
    success = await self._approve_pr(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f41afa06ea0>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
comment = 'Auto-approved by Stampbot (label: autoapprove)'
trigger_type = 'label', skip_existing_check = False, head_sha = None

    async def _approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str,
        trigger_type: str,
        skip_existing_check: bool = False,
        head_sha: str | None = None,
    ) -> bool:
        """Approve a PR and track metrics.
    
        Checks for existing active approvals first to avoid duplicate comments.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            comment: Approval comment
            trigger_type: What triggered the approval (label, chatops)
            skip_existing_check: Whether to skip duplicate active approval detection
            head_sha: Current PR head SHA, used to distinguish stale approvals
    
        Returns:
            True if successful (or already approved)
        """
        with create_span(
            "webhook.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "approval.trigger_type": trigger_type,
            },
        ) as span:
            if not skip_existing_check:
                if head_sha:
                    existing_reviews = await run_in_threadpool(
                        github_client.find_bot_approval_reviews,
                        installation_id,
                        repo_full_name,
                        pr_number,
                    )
                    existing_approvals = [
                        review["id"]
                        for review in existing_reviews
                        if self._has_current_active_approval([review], head_sha)
                    ]
                else:
                    # Check for existing active approval to avoid duplicates
                    existing_approvals = await run_in_threadpool(
                        github_client.find_bot_reviews,
                        installation_id,
                        repo_full_name,
                        pr_number,
                    )
    
                if existing_approvals:
                    logger.info(
                        "PR #%d in %s already has active approval for current head, skipping",
                        pr_number,
                        repo_full_name,
                        extra={
                            "repo": repo_full_name,
                            "pr_number": pr_number,
                            "existing_review_ids": existing_approvals,
                        },
                    )
                    add_span_attributes(
                        span,
                        {
                            "approval.result": "already_approved",
                            "approval.existing_reviews": len(existing_approvals),
                        },
                    )
                    set_span_ok(span)
                    return True
    
            start_time = time.time()
    
            success = await run_in_threadpool(
                github_client.approve_pr,
                installation_id,
                repo_full_name,
                pr_number,
                comment,
            )
    
>           duration = time.time() | start_time
                       ^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/webhook_handler.py:991: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:19:14.699342Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:19:14.700054Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:19:14.700825Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:19:14.699342Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:19:14.700054Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:19:14.700825Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.69s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 1, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1052,7 +1052,7 @@
                         pr_number,
                         extra={"repo": repo_full_name, "pr_number": pr_number},
                     )
-                    duration = time.time() - start_time
+                    duration = time.time() | start_time
                     pr_dismissal_duration_seconds.observe(duration)
                     pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                     add_span_attributes(span, {"dismissal.result": "no_reviews"})
........................................................................ [ 30%]
........................................................................ [ 60%]
...............................................F
=================================== FAILURES ===================================
_______________________ test_pr_unlabeled_no_bot_reviews _______________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f2cb15322b0>
mock_github_client = <MagicMock name='github_client' id='139829930710352'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_no_bot_reviews(webhook_handler, mock_github_client):
        """Test removing label when no bot reviews exist."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = []  # No reviews to dismiss
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:291: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:39:12.179845Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:39:12.180452Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:39:12.180892Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T05:39:12.181337Z [info     ] No bot approvals found on PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42}
2026-06-29T05:39:12.181548Z [error    ] Error dismissing approvals: unsupported operand type(s) for |: 'float' and 'float' [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=error extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for |: 'float' and 'float'"}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:39:12.179845Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:39:12.180452Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:39:12.180892Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:1050 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42}, 'event': 'No bot approvals found on PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:39:12.181337Z'}
ERROR    stampbot.webhook_handler:webhook_handler.py:1091 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for |: 'float' and 'float'"}, 'event': "Error dismissing approvals: unsupported operand type(s) for |: 'float' and 'float'", 'logger': 'stampbot.webhook_handler', 'level': 'error', 'timestamp': '2026-06-29T05:39:12.181548Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_no_bot_reviews - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 191 passed, 3 deselected, 1 warning in 2.71s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 2, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1072,7 +1072,7 @@
                     )
                     success = success and result
 
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 pr_dismissal_duration_seconds.observe(duration)
 
                 status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f95d6e55910>
mock_github_client = <MagicMock name='github_client' id='140281531368848'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:264: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:50:59.771849Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:50:59.772416Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:50:59.772854Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T04:50:59.773545Z [error    ] Error dismissing approvals: unsupported operand type(s) for |: 'float' and 'float' [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=error extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for |: 'float' and 'float'"}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:50:59.771849Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:50:59.772416Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:50:59.772854Z'}
ERROR    stampbot.webhook_handler:webhook_handler.py:1091 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for |: 'float' and 'float'"}, 'event': "Error dismissing approvals: unsupported operand type(s) for |: 'float' and 'float'", 'logger': 'stampbot.webhook_handler', 'level': 'error', 'timestamp': '2026-06-29T04:50:59.773545Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 3, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1084,7 +1084,7 @@
                 return success
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 pr_dismissal_duration_seconds.observe(duration)
                 pr_dismissals_total.labels(trigger_type=trigger_type, status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
..............F
=================================== FAILURES ===================================
_______________________ test_dismiss_approvals_exception _______________________

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fecbe947a70>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
message = 'Label autoapprove removed', trigger_type = 'label_removed'

    async def _dismiss_approvals(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
        trigger_type: str,
    ) -> bool:
        """Dismiss bot approvals on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            message: Dismissal message
            trigger_type: What triggered the dismissal (label_removed, chatops)
    
        Returns:
            True if successful
        """
        with create_span(
            "webhook.dismiss_approvals",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "dismissal.trigger_type": trigger_type,
            },
        ) as span:
            start_time = time.time()
    
            try:
                # Find all bot reviews
>               review_ids = await run_in_threadpool(
                    github_client.find_bot_reviews,
                    installation_id,
                    repo_full_name,
                    pr_number,
                )

stampbot/webhook_handler.py:1040: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/concurrency.py:34: in run_in_threadpool
    return await anyio.to_thread.run_sync(func)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/to_thread.py:63: in run_sync
    return await get_async_backend().run_sync_in_worker_thread(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:2596: in run_sync_in_worker_thread
    return await future
           ^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:1029: in run
    result = context.run(func, *args)
             ^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_reviews' id='140654785072496'>
args = (12345, 'octocat/hello-world', 42), kwargs = {}
effect = Exception('API error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fecbe947a70>
mock_github_client = <MagicMock name='github_client' id='140654785070480'>

    @pytest.mark.asyncio
    async def test_dismiss_approvals_exception(webhook_handler, mock_github_client):
        """Test _dismiss_approvals handles exceptions gracefully."""
        payload = load_fixture("pr_unlabeled_autoapprove")
    
        # Make find_bot_reviews raise an exception
        mock_github_client.find_bot_reviews.side_effect = Exception("API error")
    
>       result = await webhook_handler.handle_event("pull_request", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:944: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:116: in handle_event
    result = await self._handle_pull_request(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:350: in _handle_pull_request
    success = await self._dismiss_approvals(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fecbe947a70>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
message = 'Label autoapprove removed', trigger_type = 'label_removed'

    async def _dismiss_approvals(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
        trigger_type: str,
    ) -> bool:
        """Dismiss bot approvals on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            message: Dismissal message
            trigger_type: What triggered the dismissal (label_removed, chatops)
    
        Returns:
            True if successful
        """
        with create_span(
            "webhook.dismiss_approvals",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "dismissal.trigger_type": trigger_type,
            },
        ) as span:
            start_time = time.time()
    
            try:
                # Find all bot reviews
                review_ids = await run_in_threadpool(
                    github_client.find_bot_reviews,
                    installation_id,
                    repo_full_name,
                    pr_number,
                )
    
                add_span_attributes(span, {"dismissal.reviews_found": len(review_ids)})
    
                if not review_ids:
                    logger.info(
                        "No bot approvals found on PR #%d",
                        pr_number,
                        extra={"repo": repo_full_name, "pr_number": pr_number},
                    )
                    duration = time.time() - start_time
                    pr_dismissal_duration_seconds.observe(duration)
                    pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                    add_span_attributes(span, {"dismissal.result": "no_reviews"})
                    set_span_ok(span)
                    return True
    
                # Dismiss each review
                success = True
                for review_id in review_ids:
                    result = await run_in_threadpool(
                        github_client.dismiss_approval,
                        installation_id,
                        repo_full_name,
                        pr_number,
                        review_id,
                        message,
                    )
                    success = success and result
    
                duration = time.time() - start_time
                pr_dismissal_duration_seconds.observe(duration)
    
                status = "success" if success else "failure"
                pr_dismissals_total.labels(trigger_type=trigger_type, status=status).inc()
    
                add_span_attributes(span, {"dismissal.result": status})
                set_span_ok(span)
    
                return success
    
            except Exception as e:
>               duration = time.time() | start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/webhook_handler.py:1087: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:18:47.714086Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:18:47.714670Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:18:47.715109Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:18:47.714086Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:18:47.714670Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:18:47.715109Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_dismiss_approvals_exception - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 230 passed, 3 deselected, 1 warning in 3.47s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 0, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -988,7 +988,7 @@
                 comment,
             )
 
-            duration = time.time() - start_time
+            duration = time.time() & start_time
             pr_approval_duration_seconds.observe(duration)
 
             status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7ff6ef012ea0>
mock_github_client = <MagicMock name='github_client' id='140698549289376'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
>       result = await webhook_handler.handle_event("pull_request", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:71: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:116: in handle_event
    result = await self._handle_pull_request(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:307: in _handle_pull_request
    success = await self._approve_pr(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7ff6ef012ea0>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
comment = 'Auto-approved by Stampbot (label: autoapprove)'
trigger_type = 'label', skip_existing_check = False, head_sha = None

    async def _approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str,
        trigger_type: str,
        skip_existing_check: bool = False,
        head_sha: str | None = None,
    ) -> bool:
        """Approve a PR and track metrics.
    
        Checks for existing active approvals first to avoid duplicate comments.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            comment: Approval comment
            trigger_type: What triggered the approval (label, chatops)
            skip_existing_check: Whether to skip duplicate active approval detection
            head_sha: Current PR head SHA, used to distinguish stale approvals
    
        Returns:
            True if successful (or already approved)
        """
        with create_span(
            "webhook.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "approval.trigger_type": trigger_type,
            },
        ) as span:
            if not skip_existing_check:
                if head_sha:
                    existing_reviews = await run_in_threadpool(
                        github_client.find_bot_approval_reviews,
                        installation_id,
                        repo_full_name,
                        pr_number,
                    )
                    existing_approvals = [
                        review["id"]
                        for review in existing_reviews
                        if self._has_current_active_approval([review], head_sha)
                    ]
                else:
                    # Check for existing active approval to avoid duplicates
                    existing_approvals = await run_in_threadpool(
                        github_client.find_bot_reviews,
                        installation_id,
                        repo_full_name,
                        pr_number,
                    )
    
                if existing_approvals:
                    logger.info(
                        "PR #%d in %s already has active approval for current head, skipping",
                        pr_number,
                        repo_full_name,
                        extra={
                            "repo": repo_full_name,
                            "pr_number": pr_number,
                            "existing_review_ids": existing_approvals,
                        },
                    )
                    add_span_attributes(
                        span,
                        {
                            "approval.result": "already_approved",
                            "approval.existing_reviews": len(existing_approvals),
                        },
                    )
                    set_span_ok(span)
                    return True
    
            start_time = time.time()
    
            success = await run_in_threadpool(
                github_client.approve_pr,
                installation_id,
                repo_full_name,
                pr_number,
                comment,
            )
    
>           duration = time.time() & start_time
                       ^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/webhook_handler.py:991: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:55:55.957294Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:55:55.958054Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:55:55.958838Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:55:55.957294Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:55:55.958054Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:55:55.958838Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 1, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1052,7 +1052,7 @@
                         pr_number,
                         extra={"repo": repo_full_name, "pr_number": pr_number},
                     )
-                    duration = time.time() - start_time
+                    duration = time.time() & start_time
                     pr_dismissal_duration_seconds.observe(duration)
                     pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                     add_span_attributes(span, {"dismissal.result": "no_reviews"})
........................................................................ [ 30%]
........................................................................ [ 60%]
...............................................F
=================================== FAILURES ===================================
_______________________ test_pr_unlabeled_no_bot_reviews _______________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fe97eb4e2b0>
mock_github_client = <MagicMock name='github_client' id='140640830297424'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_no_bot_reviews(webhook_handler, mock_github_client):
        """Test removing label when no bot reviews exist."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = []  # No reviews to dismiss
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:291: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:19:44.843009Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:19:44.843619Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:19:44.844059Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T04:19:44.844505Z [info     ] No bot approvals found on PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42}
2026-06-29T04:19:44.844709Z [error    ] Error dismissing approvals: unsupported operand type(s) for &: 'float' and 'float' [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=error extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for &: 'float' and 'float'"}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:19:44.843009Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:19:44.843619Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:19:44.844059Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:1050 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42}, 'event': 'No bot approvals found on PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:19:44.844505Z'}
ERROR    stampbot.webhook_handler:webhook_handler.py:1091 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for &: 'float' and 'float'"}, 'event': "Error dismissing approvals: unsupported operand type(s) for &: 'float' and 'float'", 'logger': 'stampbot.webhook_handler', 'level': 'error', 'timestamp': '2026-06-29T04:19:44.844709Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_no_bot_reviews - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 191 passed, 3 deselected, 1 warning in 2.68s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 2, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1072,7 +1072,7 @@
                     )
                     success = success and result
 
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 pr_dismissal_duration_seconds.observe(duration)
 
                 status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fb112855910>
mock_github_client = <MagicMock name='github_client' id='140398495827344'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:264: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:04:00.849824Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:04:00.850390Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:04:00.850819Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T05:04:00.851526Z [error    ] Error dismissing approvals: unsupported operand type(s) for &: 'float' and 'float' [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=error extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for &: 'float' and 'float'"}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:04:00.849824Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:04:00.850390Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:04:00.850819Z'}
ERROR    stampbot.webhook_handler:webhook_handler.py:1091 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for &: 'float' and 'float'"}, 'event': "Error dismissing approvals: unsupported operand type(s) for &: 'float' and 'float'", 'logger': 'stampbot.webhook_handler', 'level': 'error', 'timestamp': '2026-06-29T05:04:00.851526Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 3, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1084,7 +1084,7 @@
                 return success
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 pr_dismissal_duration_seconds.observe(duration)
                 pr_dismissals_total.labels(trigger_type=trigger_type, status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
..............F
=================================== FAILURES ===================================
_______________________ test_dismiss_approvals_exception _______________________

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fa5e9fe0350>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
message = 'Label autoapprove removed', trigger_type = 'label_removed'

    async def _dismiss_approvals(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
        trigger_type: str,
    ) -> bool:
        """Dismiss bot approvals on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            message: Dismissal message
            trigger_type: What triggered the dismissal (label_removed, chatops)
    
        Returns:
            True if successful
        """
        with create_span(
            "webhook.dismiss_approvals",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "dismissal.trigger_type": trigger_type,
            },
        ) as span:
            start_time = time.time()
    
            try:
                # Find all bot reviews
>               review_ids = await run_in_threadpool(
                    github_client.find_bot_reviews,
                    installation_id,
                    repo_full_name,
                    pr_number,
                )

stampbot/webhook_handler.py:1040: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/concurrency.py:34: in run_in_threadpool
    return await anyio.to_thread.run_sync(func)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/to_thread.py:63: in run_sync
    return await get_async_backend().run_sync_in_worker_thread(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:2596: in run_sync_in_worker_thread
    return await future
           ^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:1029: in run
    result = context.run(func, *args)
             ^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_reviews' id='140350570253680'>
args = (12345, 'octocat/hello-world', 42), kwargs = {}
effect = Exception('API error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fa5e9fe0350>
mock_github_client = <MagicMock name='github_client' id='140350570251664'>

    @pytest.mark.asyncio
    async def test_dismiss_approvals_exception(webhook_handler, mock_github_client):
        """Test _dismiss_approvals handles exceptions gracefully."""
        payload = load_fixture("pr_unlabeled_autoapprove")
    
        # Make find_bot_reviews raise an exception
        mock_github_client.find_bot_reviews.side_effect = Exception("API error")
    
>       result = await webhook_handler.handle_event("pull_request", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:944: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:116: in handle_event
    result = await self._handle_pull_request(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:350: in _handle_pull_request
    success = await self._dismiss_approvals(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fa5e9fe0350>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
message = 'Label autoapprove removed', trigger_type = 'label_removed'

    async def _dismiss_approvals(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
        trigger_type: str,
    ) -> bool:
        """Dismiss bot approvals on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            message: Dismissal message
            trigger_type: What triggered the dismissal (label_removed, chatops)
    
        Returns:
            True if successful
        """
        with create_span(
            "webhook.dismiss_approvals",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "dismissal.trigger_type": trigger_type,
            },
        ) as span:
            start_time = time.time()
    
            try:
                # Find all bot reviews
                review_ids = await run_in_threadpool(
                    github_client.find_bot_reviews,
                    installation_id,
                    repo_full_name,
                    pr_number,
                )
    
                add_span_attributes(span, {"dismissal.reviews_found": len(review_ids)})
    
                if not review_ids:
                    logger.info(
                        "No bot approvals found on PR #%d",
                        pr_number,
                        extra={"repo": repo_full_name, "pr_number": pr_number},
                    )
                    duration = time.time() - start_time
                    pr_dismissal_duration_seconds.observe(duration)
                    pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                    add_span_attributes(span, {"dismissal.result": "no_reviews"})
                    set_span_ok(span)
                    return True
    
                # Dismiss each review
                success = True
                for review_id in review_ids:
                    result = await run_in_threadpool(
                        github_client.dismiss_approval,
                        installation_id,
                        repo_full_name,
                        pr_number,
                        review_id,
                        message,
                    )
                    success = success and result
    
                duration = time.time() - start_time
                pr_dismissal_duration_seconds.observe(duration)
    
                status = "success" if success else "failure"
                pr_dismissals_total.labels(trigger_type=trigger_type, status=status).inc()
    
                add_span_attributes(span, {"dismissal.result": status})
                set_span_ok(span)
    
                return success
    
            except Exception as e:
>               duration = time.time() & start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/webhook_handler.py:1087: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:01:31.373102Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:01:31.373679Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:01:31.374110Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:01:31.373102Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:01:31.373679Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:01:31.374110Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_dismiss_approvals_exception - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 230 passed, 3 deselected, 1 warning in 3.48s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 0, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -988,7 +988,7 @@
                 comment,
             )
 
-            duration = time.time() - start_time
+            duration = time.time() ^ start_time
             pr_approval_duration_seconds.observe(duration)
 
             status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fa7b2042ea0>
mock_github_client = <MagicMock name='github_client' id='140358221562272'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
>       result = await webhook_handler.handle_event("pull_request", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:71: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:116: in handle_event
    result = await self._handle_pull_request(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:307: in _handle_pull_request
    success = await self._approve_pr(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fa7b2042ea0>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
comment = 'Auto-approved by Stampbot (label: autoapprove)'
trigger_type = 'label', skip_existing_check = False, head_sha = None

    async def _approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str,
        trigger_type: str,
        skip_existing_check: bool = False,
        head_sha: str | None = None,
    ) -> bool:
        """Approve a PR and track metrics.
    
        Checks for existing active approvals first to avoid duplicate comments.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            comment: Approval comment
            trigger_type: What triggered the approval (label, chatops)
            skip_existing_check: Whether to skip duplicate active approval detection
            head_sha: Current PR head SHA, used to distinguish stale approvals
    
        Returns:
            True if successful (or already approved)
        """
        with create_span(
            "webhook.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "approval.trigger_type": trigger_type,
            },
        ) as span:
            if not skip_existing_check:
                if head_sha:
                    existing_reviews = await run_in_threadpool(
                        github_client.find_bot_approval_reviews,
                        installation_id,
                        repo_full_name,
                        pr_number,
                    )
                    existing_approvals = [
                        review["id"]
                        for review in existing_reviews
                        if self._has_current_active_approval([review], head_sha)
                    ]
                else:
                    # Check for existing active approval to avoid duplicates
                    existing_approvals = await run_in_threadpool(
                        github_client.find_bot_reviews,
                        installation_id,
                        repo_full_name,
                        pr_number,
                    )
    
                if existing_approvals:
                    logger.info(
                        "PR #%d in %s already has active approval for current head, skipping",
                        pr_number,
                        repo_full_name,
                        extra={
                            "repo": repo_full_name,
                            "pr_number": pr_number,
                            "existing_review_ids": existing_approvals,
                        },
                    )
                    add_span_attributes(
                        span,
                        {
                            "approval.result": "already_approved",
                            "approval.existing_reviews": len(existing_approvals),
                        },
                    )
                    set_span_ok(span)
                    return True
    
            start_time = time.time()
    
            success = await run_in_threadpool(
                github_client.approve_pr,
                installation_id,
                repo_full_name,
                pr_number,
                comment,
            )
    
>           duration = time.time() ^ start_time
                       ^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/webhook_handler.py:991: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:17:59.265031Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:17:59.265782Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:17:59.266543Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:17:59.265031Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:17:59.265782Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:17:59.266543Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 1, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1052,7 +1052,7 @@
                         pr_number,
                         extra={"repo": repo_full_name, "pr_number": pr_number},
                     )
-                    duration = time.time() - start_time
+                    duration = time.time() ^ start_time
                     pr_dismissal_duration_seconds.observe(duration)
                     pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                     add_span_attributes(span, {"dismissal.result": "no_reviews"})
........................................................................ [ 30%]
........................................................................ [ 60%]
...............................................F
=================================== FAILURES ===================================
_______________________ test_pr_unlabeled_no_bot_reviews _______________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fcc3f45a2b0>
mock_github_client = <MagicMock name='github_client' id='140515211990352'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_no_bot_reviews(webhook_handler, mock_github_client):
        """Test removing label when no bot reviews exist."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = []  # No reviews to dismiss
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:291: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:44:33.288291Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:44:33.288858Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:44:33.289303Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T05:44:33.289729Z [info     ] No bot approvals found on PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42}
2026-06-29T05:44:33.289927Z [error    ] Error dismissing approvals: unsupported operand type(s) for ^: 'float' and 'float' [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=error extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for ^: 'float' and 'float'"}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:44:33.288291Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:44:33.288858Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:44:33.289303Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:1050 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42}, 'event': 'No bot approvals found on PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:44:33.289729Z'}
ERROR    stampbot.webhook_handler:webhook_handler.py:1091 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for ^: 'float' and 'float'"}, 'event': "Error dismissing approvals: unsupported operand type(s) for ^: 'float' and 'float'", 'logger': 'stampbot.webhook_handler', 'level': 'error', 'timestamp': '2026-06-29T05:44:33.289927Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_no_bot_reviews - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 191 passed, 3 deselected, 1 warning in 2.68s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 2, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1072,7 +1072,7 @@
                     )
                     success = success and result
 
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 pr_dismissal_duration_seconds.observe(duration)
 
                 status = "success" if success else "failure"
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f585e07d910>
mock_github_client = <MagicMock name='github_client' id='140017510581648'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:264: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:49:25.445886Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:49:25.446474Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:49:25.446904Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T05:49:25.447573Z [error    ] Error dismissing approvals: unsupported operand type(s) for ^: 'float' and 'float' [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=error extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for ^: 'float' and 'float'"}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:49:25.445886Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:49:25.446474Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:49:25.446904Z'}
ERROR    stampbot.webhook_handler:webhook_handler.py:1091 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'error': "unsupported operand type(s) for ^: 'float' and 'float'"}, 'event': "Error dismissing approvals: unsupported operand type(s) for ^: 'float' and 'float'", 'logger': 'stampbot.webhook_handler', 'level': 'error', 'timestamp': '2026-06-29T05:49:25.447573Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 3, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1084,7 +1084,7 @@
                 return success
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 pr_dismissal_duration_seconds.observe(duration)
                 pr_dismissals_total.labels(trigger_type=trigger_type, status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
..............F
=================================== FAILURES ===================================
_______________________ test_dismiss_approvals_exception _______________________

self = <stampbot.webhook_handler.WebhookHandler object at 0x7efe20690350>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
message = 'Label autoapprove removed', trigger_type = 'label_removed'

    async def _dismiss_approvals(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
        trigger_type: str,
    ) -> bool:
        """Dismiss bot approvals on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            message: Dismissal message
            trigger_type: What triggered the dismissal (label_removed, chatops)
    
        Returns:
            True if successful
        """
        with create_span(
            "webhook.dismiss_approvals",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "dismissal.trigger_type": trigger_type,
            },
        ) as span:
            start_time = time.time()
    
            try:
                # Find all bot reviews
>               review_ids = await run_in_threadpool(
                    github_client.find_bot_reviews,
                    installation_id,
                    repo_full_name,
                    pr_number,
                )

stampbot/webhook_handler.py:1040: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/concurrency.py:34: in run_in_threadpool
    return await anyio.to_thread.run_sync(func)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/to_thread.py:63: in run_sync
    return await get_async_backend().run_sync_in_worker_thread(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:2596: in run_sync_in_worker_thread
    return await future
           ^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:1029: in run
    result = context.run(func, *args)
             ^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_reviews' id='139629929205104'>
args = (12345, 'octocat/hello-world', 42), kwargs = {}
effect = Exception('API error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7efe20690350>
mock_github_client = <MagicMock name='github_client' id='139629929203088'>

    @pytest.mark.asyncio
    async def test_dismiss_approvals_exception(webhook_handler, mock_github_client):
        """Test _dismiss_approvals handles exceptions gracefully."""
        payload = load_fixture("pr_unlabeled_autoapprove")
    
        # Make find_bot_reviews raise an exception
        mock_github_client.find_bot_reviews.side_effect = Exception("API error")
    
>       result = await webhook_handler.handle_event("pull_request", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:944: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:116: in handle_event
    result = await self._handle_pull_request(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:350: in _handle_pull_request
    success = await self._dismiss_approvals(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7efe20690350>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
message = 'Label autoapprove removed', trigger_type = 'label_removed'

    async def _dismiss_approvals(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
        trigger_type: str,
    ) -> bool:
        """Dismiss bot approvals on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            message: Dismissal message
            trigger_type: What triggered the dismissal (label_removed, chatops)
    
        Returns:
            True if successful
        """
        with create_span(
            "webhook.dismiss_approvals",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "dismissal.trigger_type": trigger_type,
            },
        ) as span:
            start_time = time.time()
    
            try:
                # Find all bot reviews
                review_ids = await run_in_threadpool(
                    github_client.find_bot_reviews,
                    installation_id,
                    repo_full_name,
                    pr_number,
                )
    
                add_span_attributes(span, {"dismissal.reviews_found": len(review_ids)})
    
                if not review_ids:
                    logger.info(
                        "No bot approvals found on PR #%d",
                        pr_number,
                        extra={"repo": repo_full_name, "pr_number": pr_number},
                    )
                    duration = time.time() - start_time
                    pr_dismissal_duration_seconds.observe(duration)
                    pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                    add_span_attributes(span, {"dismissal.result": "no_reviews"})
                    set_span_ok(span)
                    return True
    
                # Dismiss each review
                success = True
                for review_id in review_ids:
                    result = await run_in_threadpool(
                        github_client.dismiss_approval,
                        installation_id,
                        repo_full_name,
                        pr_number,
                        review_id,
                        message,
                    )
                    success = success and result
    
                duration = time.time() - start_time
                pr_dismissal_duration_seconds.observe(duration)
    
                status = "success" if success else "failure"
                pr_dismissals_total.labels(trigger_type=trigger_type, status=status).inc()
    
                add_span_attributes(span, {"dismissal.result": status})
                set_span_ok(span)
    
                return success
    
            except Exception as e:
>               duration = time.time() ^ start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/webhook_handler.py:1087: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:11:17.666736Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:11:17.667288Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:11:17.667726Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:11:17.666736Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:11:17.667288Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:11:17.667726Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_dismiss_approvals_exception - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 230 passed, 3 deselected, 1 warning in 3.44s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 0, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -112,7 +112,7 @@
             )
 
             # Route to appropriate handler
-            if event_type == "pull_request":
+            if event_type != "pull_request":
                 result = await self._handle_pull_request(payload)
             elif event_type == "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7fd61967ecf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'error' == 'ok'
E         
E         - ok
E         + error

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:35:04.237941Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T05:35:04.238186Z [warning  ] Missing required fields in PR event [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning client_ip=testclient
2026-06-29T05:35:04.239084Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:35:04.237941Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:164 {'event': 'Missing required fields in PR event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T05:35:04.238186Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'error' == 'ok'
  
  - ok
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.36s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 1, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -114,7 +114,7 @@
             # Route to appropriate handler
             if event_type == "pull_request":
                 result = await self._handle_pull_request(payload)
-            elif event_type == "pull_request_review_comment":
+            elif event_type != "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
             elif event_type == "issue_comment":
                 # Issue comments can be on PRs too
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7f585d776cf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'ignored' == 'ok'
E         
E         - ok
E         + ignored

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:25:35.859280Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T04:25:35.860119Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:25:35.859280Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'ignored' == 'ok'
  
  - ok
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.35s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 2, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -116,7 +116,7 @@
                 result = await self._handle_pull_request(payload)
             elif event_type == "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
-            elif event_type == "issue_comment":
+            elif event_type != "issue_comment":
                 # Issue comments can be on PRs too
                 if "pull_request" in payload.get("issue", {}):
                     result = await self._handle_pr_comment(payload)
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7f9ddf982cf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'ignored' == 'ok'
E         
E         - ok
E         + ignored

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:56:56.998530Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T04:56:56.999427Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:56:56.998530Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'ignored' == 'ok'
  
  - ok
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.38s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 3, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -122,7 +122,7 @@
                     result = await self._handle_pr_comment(payload)
                 else:
                     result = {"status": "ignored", "message": "Not a PR comment"}
-            elif event_type == "ping":
+            elif event_type != "ping":
                 result = {"status": "ok", "message": "pong"}
             else:
                 result = {"status": "ignored", "message": f"Event type {event_type} not handled"}
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7ff65ec46cf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'ignored' == 'ok'
E         
E         - ok
E         + ignored

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:39:58.594775Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T04:39:58.595659Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:39:58.594775Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'ignored' == 'ok'
  
  - ok
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.35s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 4, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -190,7 +190,7 @@
                     },
                 )
 
-                if action == "opened":
+                if action != "opened":
                     await run_in_threadpool(
                         github_client.create_pr_review_comment,
                         installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.F
=================================== FAILURES ===================================
____________________ test_invalid_repo_config_posts_review _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fe1a5ae04d0>
mock_github_client = <MagicMock name='github_client' id='140607123873408'>

    @pytest.mark.asyncio
    async def test_invalid_repo_config_posts_review(webhook_handler, mock_github_client):
        """Test invalid repo config logs and posts a review comment."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        mock_github_client.get_repo_file.return_value = 'chatops_required_permission = "invalid"'
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "error"
        assert "invalid" in result["message"].lower()
>       mock_github_client.create_pr_review_comment.assert_called_once()

tests/test_webhook_handler.py:727: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.create_pr_review_comment' id='140607123866016'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'create_pr_review_comment' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:23:49.373030Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:23:49.374243Z [warning  ] Invalid stampbot.toml in octocat/hello-world: Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning extra={'repo': 'octocat/hello-world', 'error': 'Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:23:49.373030Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:179 {'extra': {'repo': 'octocat/hello-world', 'error': 'Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin'}, 'event': 'Invalid stampbot.toml in octocat/hello-world: Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T05:23:49.374243Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_invalid_repo_config_posts_review - AssertionError: Expected 'create_pr_review_comment' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 217 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 5, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -209,7 +209,7 @@
                     "message": "Invalid repository configuration",
                 }
 
-            if action == "opened":
+            if action != "opened":
                 for label in repo_config.approval_labels:
                     label_exists = await run_in_threadpool(
                         github_client.repo_has_label,
........................................................................ [ 30%]
........................................................................ [ 60%]
...................................F
=================================== FAILURES ===================================
__________________ test_pr_opened_missing_label_logs_warning ___________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f050e60ee70>
mock_github_client = <MagicMock name='github_client' id='139659696188992'>

    @pytest.mark.asyncio
    async def test_pr_opened_missing_label_logs_warning(webhook_handler, mock_github_client):
        """Test missing approval label triggers label check."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        mock_github_client.repo_has_label.return_value = False
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
>       assert mock_github_client.repo_has_label.call_count == 2
E       AssertionError: assert 0 == 2
E        +  where 0 = <MagicMock name='github_client.repo_has_label' id='139659696192352'>.call_count
E        +    where <MagicMock name='github_client.repo_has_label' id='139659696192352'> = <MagicMock name='github_client' id='139659696188992'>.repo_has_label

tests/test_webhook_handler.py:104: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:30:50.548418Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:30:50.548963Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:30:50.549421Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:30:50.548418Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:30:50.548963Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:30:50.549421Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_missing_label_logs_warning - AssertionError: assert 0 == 2
 +  where 0 = <MagicMock name='github_client.repo_has_label' id='139659696192352'>.call_count
 +    where <MagicMock name='github_client.repo_has_label' id='139659696192352'> = <MagicMock name='github_client' id='139659696188992'>.repo_has_label
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 179 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 6, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -332,7 +332,7 @@
                     }
 
             # Check if we should remove approval when label is removed
-            if repo_config.auto_approve_on_label and action == "unlabeled":
+            if repo_config.auto_approve_on_label and action != "unlabeled":
                 removed_label = payload.get("label", {}).get("name")
                 if removed_label in repo_config.approval_labels:
                     logger.info(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f8e0d78d910>
mock_github_client = <MagicMock name='github_client' id='140248087266704'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:264: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:45:20.922063Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:45:20.922641Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:45:20.922063Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:45:20.922641Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.68s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 7, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -418,7 +418,7 @@
             return True, False
 
         added_label = payload.get("label", {}).get("name")
-        if action == "labeled" and added_label in repo_config.approval_labels:
+        if action != "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
         if action == "synchronize" and not repo_config.reapprove:
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................F
=================================== FAILURES ===================================
_________________________ test_pr_labeled_autoapprove __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f5aab189260>
mock_github_client = <MagicMock name='github_client' id='140027395037840'>

    @pytest.mark.asyncio
    async def test_pr_labeled_autoapprove(webhook_handler, mock_github_client):
        """Test adding autoapprove label triggers approval."""
        payload = load_fixture("pr_labeled_autoapprove")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:126: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:14:13.727751Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:14:13.728324Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:14:13.727751Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:14:13.728324Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_autoapprove - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 181 passed, 3 deselected, 1 warning in 2.66s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 8, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -421,7 +421,7 @@
         if action == "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
-        if action == "synchronize" and not repo_config.reapprove:
+        if action != "synchronize" and not repo_config.reapprove:
             return False, False
 
         if action not in ("labeled", "synchronize"):
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_with_approval_label_ignored __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f32d95a9950>
mock_github_client = <MagicMock name='github_client' id='139856373169664'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_with_approval_label_ignored(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes do not re-approve just because an approval label exists."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "ignored"
        assert "no action" in result["message"].lower()
>       mock_github_client.find_bot_approval_reviews.assert_called_once()

tests/test_webhook_handler.py:144: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_approval_reviews' id='139856371830464'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:48:27.711267Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:48:27.711826Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:48:27.711267Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:48:27.711826Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_with_approval_label_ignored - AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 182 passed, 3 deselected, 1 warning in 2.72s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 9, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -474,7 +474,7 @@
                 continue
 
             review_commit = review.get("commit_id")
-            if not head_sha or not review_commit or review_commit == head_sha:
+            if not head_sha or not review_commit or review_commit != head_sha:
                 return True
 
         return False
........................................................................ [ 30%]
........................................................................ [ 60%]
.........................................F
=================================== FAILURES ===================================
____________ test_pr_synchronize_reapprove_enabled_for_stale_review ____________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7feec5995e50>
mock_github_client = <MagicMock name='github_client' id='140663489881360'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_enabled_for_stale_review(
        webhook_handler, mock_github_client
    ):
        """Test new commits re-approve when reapprove is enabled and prior approval is stale."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
        mock_github_client.get_repo_file.return_value = "reapprove = true"
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "APPROVED", "commit_id": "oldsha"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:197: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:22:39.583811Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:22:39.583811Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_enabled_for_stale_review - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 185 passed, 3 deselected, 1 warning in 2.68s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 10, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -573,7 +573,7 @@
             command = command_match.group(1).lower()
             add_span_attributes(span, {"chatops.command": command})
 
-            if command == "help":
+            if command != "help":
                 success = await self._post_help(
                     installation_id,
                     repo_full_name,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f9986f4ac50>
mock_github_client = <MagicMock name='github_client' id='140297385140176'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
>       assert "approved" in result["message"].lower()
E       AssertionError: assert 'approved' in 'help message posted'
E        +  where 'help message posted' = <built-in method lower of str object at 0x7f9987c57070>()
E        +    where <built-in method lower of str object at 0x7f9987c57070> = 'Help message posted'.lower

tests/test_webhook_handler.py:372: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:46:38.389770Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:46:38.390359Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:46:38.389770Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:46:38.390359Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'approved' in 'help message posted'
 +  where 'help message posted' = <built-in method lower of str object at 0x7f9987c57070>()
 +    where <built-in method lower of str object at 0x7f9987c57070> = 'Help message posted'.lower
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.71s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 11, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -724,7 +724,7 @@
 
                 org_repo_full_name = None
                 if (
-                    owner_type == "Organization"
+                    owner_type != "Organization"
                     and owner_login
                     and repo_full_name != f"{owner_login}/.github"
                 ):
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................................F
=================================== FAILURES ===================================
_____________________ test_repo_config_uses_default_branch _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f4f43580d70>
mock_github_client = <MagicMock name='github_client' id='139978407608400'>

    @pytest.mark.asyncio
    async def test_repo_config_uses_default_branch(webhook_handler, mock_github_client):
        """Test repo config is loaded from the default branch."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["repository"]["default_branch"] = "develop"
        payload["pull_request"]["base"]["ref"] = "release"
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        args = mock_github_client.get_repo_file.call_args[0]
>       assert args[3] == "develop"
E       AssertionError: assert None == 'develop'

tests/test_webhook_handler.py:643: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:32:17.814493Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:32:17.815179Z [info     ] No stampbot.toml found in octocat/hello-world or octocat/.github, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': 'octocat/.github'}
2026-06-29T05:32:17.815875Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:32:17.814493Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': 'octocat/.github'}, 'event': 'No stampbot.toml found in octocat/hello-world or octocat/.github, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:32:17.815179Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:32:17.815875Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_repo_config_uses_default_branch - AssertionError: assert None == 'develop'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 213 passed, 3 deselected, 1 warning in 3.18s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 0, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -112,7 +112,7 @@
             )
 
             # Route to appropriate handler
-            if event_type == "pull_request":
+            if event_type < "pull_request":
                 result = await self._handle_pull_request(payload)
             elif event_type == "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7fdef4986cf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'error' == 'ok'
E         
E         - ok
E         + error

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:27:58.939923Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T05:27:58.940159Z [warning  ] Missing required fields in PR event [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning client_ip=testclient
2026-06-29T05:27:58.941049Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:27:58.939923Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:164 {'event': 'Missing required fields in PR event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T05:27:58.940159Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'error' == 'ok'
  
  - ok
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.52s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 1, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -114,7 +114,7 @@
             # Route to appropriate handler
             if event_type == "pull_request":
                 result = await self._handle_pull_request(payload)
-            elif event_type == "pull_request_review_comment":
+            elif event_type < "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
             elif event_type == "issue_comment":
                 # Issue comments can be on PRs too
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7fe19a862cf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'ignored' == 'ok'
E         
E         - ok
E         + ignored

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:18:27.480906Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T04:18:27.481795Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:18:27.480906Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'ignored' == 'ok'
  
  - ok
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.37s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 2, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -116,7 +116,7 @@
                 result = await self._handle_pull_request(payload)
             elif event_type == "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
-            elif event_type == "issue_comment":
+            elif event_type < "issue_comment":
                 # Issue comments can be on PRs too
                 if "pull_request" in payload.get("issue", {}):
                     result = await self._handle_pr_comment(payload)
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f8f39527a50>
mock_github_client = <MagicMock name='github_client' id='140253122502608'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:29:13.616950Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:29:13.616950Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.71s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 3, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -122,7 +122,7 @@
                     result = await self._handle_pr_comment(payload)
                 else:
                     result = {"status": "ignored", "message": "Not a PR comment"}
-            elif event_type == "ping":
+            elif event_type < "ping":
                 result = {"status": "ok", "message": "pong"}
             else:
                 result = {"status": "ignored", "message": f"Event type {event_type} not handled"}
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7fe67225acf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'ignored' == 'ok'
E         
E         - ok
E         + ignored

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:39:02.807931Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T05:39:02.808817Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:39:02.807931Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'ignored' == 'ok'
  
  - ok
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.39s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 4, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -190,7 +190,7 @@
                     },
                 )
 
-                if action == "opened":
+                if action < "opened":
                     await run_in_threadpool(
                         github_client.create_pr_review_comment,
                         installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.F
=================================== FAILURES ===================================
____________________ test_invalid_repo_config_posts_review _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f38d1dd44d0>
mock_github_client = <MagicMock name='github_client' id='139882015694464'>

    @pytest.mark.asyncio
    async def test_invalid_repo_config_posts_review(webhook_handler, mock_github_client):
        """Test invalid repo config logs and posts a review comment."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        mock_github_client.get_repo_file.return_value = 'chatops_required_permission = "invalid"'
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "error"
        assert "invalid" in result["message"].lower()
>       mock_github_client.create_pr_review_comment.assert_called_once()

tests/test_webhook_handler.py:727: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.create_pr_review_comment' id='139882015687072'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'create_pr_review_comment' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:01:14.608834Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:01:14.610002Z [warning  ] Invalid stampbot.toml in octocat/hello-world: Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning extra={'repo': 'octocat/hello-world', 'error': 'Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:01:14.608834Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:179 {'extra': {'repo': 'octocat/hello-world', 'error': 'Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin'}, 'event': 'Invalid stampbot.toml in octocat/hello-world: Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T05:01:14.610002Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_invalid_repo_config_posts_review - AssertionError: Expected 'create_pr_review_comment' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 217 passed, 3 deselected, 1 warning in 3.27s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 5, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -209,7 +209,7 @@
                     "message": "Invalid repository configuration",
                 }
 
-            if action == "opened":
+            if action < "opened":
                 for label in repo_config.approval_labels:
                     label_exists = await run_in_threadpool(
                         github_client.repo_has_label,
........................................................................ [ 30%]
........................................................................ [ 60%]
...................................F
=================================== FAILURES ===================================
__________________ test_pr_opened_missing_label_logs_warning ___________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f0d167e2e70>
mock_github_client = <MagicMock name='github_client' id='139694200483392'>

    @pytest.mark.asyncio
    async def test_pr_opened_missing_label_logs_warning(webhook_handler, mock_github_client):
        """Test missing approval label triggers label check."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        mock_github_client.repo_has_label.return_value = False
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
>       assert mock_github_client.repo_has_label.call_count == 2
E       AssertionError: assert 0 == 2
E        +  where 0 = <MagicMock name='github_client.repo_has_label' id='139694200486752'>.call_count
E        +    where <MagicMock name='github_client.repo_has_label' id='139694200486752'> = <MagicMock name='github_client' id='139694200483392'>.repo_has_label

tests/test_webhook_handler.py:104: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:06:13.197786Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:06:13.198384Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:06:13.198819Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:06:13.197786Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:06:13.198384Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:06:13.198819Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_missing_label_logs_warning - AssertionError: assert 0 == 2
 +  where 0 = <MagicMock name='github_client.repo_has_label' id='139694200486752'>.call_count
 +    where <MagicMock name='github_client.repo_has_label' id='139694200486752'> = <MagicMock name='github_client' id='139694200483392'>.repo_has_label
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 179 passed, 3 deselected, 1 warning in 2.66s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 6, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -332,7 +332,7 @@
                     }
 
             # Check if we should remove approval when label is removed
-            if repo_config.auto_approve_on_label and action == "unlabeled":
+            if repo_config.auto_approve_on_label and action < "unlabeled":
                 removed_label = payload.get("label", {}).get("name")
                 if removed_label in repo_config.approval_labels:
                     logger.info(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f2cdf505910>
mock_github_client = <MagicMock name='github_client' id='139830701016464'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:264: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:51:44.571952Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:51:44.572526Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:51:44.571952Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:51:44.572526Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 7, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -418,7 +418,7 @@
             return True, False
 
         added_label = payload.get("label", {}).get("name")
-        if action == "labeled" and added_label in repo_config.approval_labels:
+        if action < "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
         if action == "synchronize" and not repo_config.reapprove:
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................F
=================================== FAILURES ===================================
_________________________ test_pr_labeled_autoapprove __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f730ba61260>
mock_github_client = <MagicMock name='github_client' id='140132094155408'>

    @pytest.mark.asyncio
    async def test_pr_labeled_autoapprove(webhook_handler, mock_github_client):
        """Test adding autoapprove label triggers approval."""
        payload = load_fixture("pr_labeled_autoapprove")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:126: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:49:59.804376Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T04:49:59.804923Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:49:59.804376Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:49:59.804923Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_autoapprove - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 181 passed, 3 deselected, 1 warning in 2.64s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 8, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -421,7 +421,7 @@
         if action == "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
-        if action == "synchronize" and not repo_config.reapprove:
+        if action < "synchronize" and not repo_config.reapprove:
             return False, False
 
         if action not in ("labeled", "synchronize"):
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_with_approval_label_ignored __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f05ed3cd950>
mock_github_client = <MagicMock name='github_client' id='139663443721728'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_with_approval_label_ignored(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes do not re-approve just because an approval label exists."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "ignored"
        assert "no action" in result["message"].lower()
>       mock_github_client.find_bot_approval_reviews.assert_called_once()

tests/test_webhook_handler.py:144: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_approval_reviews' id='139663441432256'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:50:54.684529Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T04:50:54.685083Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:50:54.684529Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:50:54.685083Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_with_approval_label_ignored - AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 182 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 9, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -474,7 +474,7 @@
                 continue
 
             review_commit = review.get("commit_id")
-            if not head_sha or not review_commit or review_commit == head_sha:
+            if not head_sha or not review_commit or review_commit < head_sha:
                 return True
 
         return False
........................................................................ [ 30%]
........................................................................ [ 60%]
..........................................F
=================================== FAILURES ===================================
_________ test_pr_synchronize_reapprove_enabled_current_review_ignored _________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fb89f646b30>
mock_github_client = <MagicMock name='github_client' id='140430922233040'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_enabled_current_review_ignored(
        webhook_handler, mock_github_client
    ):
        """Test new commits do not re-approve when current head already has approval."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
        mock_github_client.get_repo_file.return_value = "reapprove = true"
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "APPROVED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:217: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:28:49.163466Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
2026-06-29T05:28:49.164533Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:28:49.163466Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:28:49.164533Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_enabled_current_review_ignored - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 186 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 10, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -573,7 +573,7 @@
             command = command_match.group(1).lower()
             add_span_attributes(span, {"chatops.command": command})
 
-            if command == "help":
+            if command < "help":
                 success = await self._post_help(
                     installation_id,
                     repo_full_name,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fe05674bcd0>
mock_github_client = <MagicMock name='github_client' id='140601503637456'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
>       assert "approved" in result["message"].lower()
E       AssertionError: assert 'approved' in 'help message posted'
E        +  where 'help message posted' = <built-in method lower of str object at 0x7fe056a557f0>()
E        +    where <built-in method lower of str object at 0x7fe056a557f0> = 'Help message posted'.lower

tests/test_webhook_handler.py:372: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:36:03.115961Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:36:03.116570Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:36:03.115961Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:36:03.116570Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'approved' in 'help message posted'
 +  where 'help message posted' = <built-in method lower of str object at 0x7fe056a557f0>()
 +    where <built-in method lower of str object at 0x7fe056a557f0> = 'Help message posted'.lower
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.72s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 11, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -724,7 +724,7 @@
 
                 org_repo_full_name = None
                 if (
-                    owner_type == "Organization"
+                    owner_type < "Organization"
                     and owner_login
                     and repo_full_name != f"{owner_login}/.github"
                 ):
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................................................F
=================================== FAILURES ===================================
_____________________ test_org_github_repo_config_fallback _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f1c51b10f50>
mock_github_client = <MagicMock name='github_client' id='139759606986272'>

    @pytest.mark.asyncio
    async def test_org_github_repo_config_fallback(webhook_handler, mock_github_client):
        """Test org .github stampbot.toml is used when repo config is missing."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["repository"]["full_name"] = "acme/widgets"
        payload["repository"]["default_branch"] = "main"
        payload["repository"]["owner"] = {"login": "acme", "type": "Organization"}
        payload["pull_request"]["labels"] = [{"name": "org-approve"}]
    
        def get_repo_file_side_effect(_installation_id, repo_full_name, _file_path, _ref):
            if repo_full_name == "acme/widgets":
                return None
            if repo_full_name == "acme/.github":
                return 'approval_labels = ["org-approve"]'
            return None
    
        mock_github_client.get_repo_file.side_effect = get_repo_file_side_effect
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:666: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:01:44.842299Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:01:44.842870Z [info     ] No stampbot.toml found in acme/widgets, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'acme/widgets', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:01:44.842299Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'acme/widgets', 'org_repo': None}, 'event': 'No stampbot.toml found in acme/widgets, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:01:44.842870Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_org_github_repo_config_fallback - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 214 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 0, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -112,7 +112,7 @@
             )
 
             # Route to appropriate handler
-            if event_type == "pull_request":
+            if event_type <= "pull_request":
                 result = await self._handle_pull_request(payload)
             elif event_type == "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7ffad8d56cf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'error' == 'ok'
E         
E         - ok
E         + error

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:31:01.284101Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T05:31:01.284351Z [warning  ] Missing required fields in PR event [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning client_ip=testclient
2026-06-29T05:31:01.285198Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:31:01.284101Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:164 {'event': 'Missing required fields in PR event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T05:31:01.284351Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'error' == 'ok'
  
  - ok
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.37s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 1, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -114,7 +114,7 @@
             # Route to appropriate handler
             if event_type == "pull_request":
                 result = await self._handle_pull_request(payload)
-            elif event_type == "pull_request_review_comment":
+            elif event_type <= "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
             elif event_type == "issue_comment":
                 # Issue comments can be on PRs too
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7f7722d8acf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'ignored' == 'ok'
E         
E         - ok
E         + ignored

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:11:57.347260Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T05:11:57.348112Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:11:57.347260Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'ignored' == 'ok'
  
  - ok
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.36s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 2, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -116,7 +116,7 @@
                 result = await self._handle_pull_request(payload)
             elif event_type == "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
-            elif event_type == "issue_comment":
+            elif event_type <= "issue_comment":
                 # Issue comments can be on PRs too
                 if "pull_request" in payload.get("issue", {}):
                     result = await self._handle_pr_comment(payload)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 3, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -122,7 +122,7 @@
                     result = await self._handle_pr_comment(payload)
                 else:
                     result = {"status": "ignored", "message": "Not a PR comment"}
-            elif event_type == "ping":
+            elif event_type <= "ping":
                 result = {"status": "ok", "message": "pong"}
             else:
                 result = {"status": "ignored", "message": f"Event type {event_type} not handled"}
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 4, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -190,7 +190,7 @@
                     },
                 )
 
-                if action == "opened":
+                if action <= "opened":
                     await run_in_threadpool(
                         github_client.create_pr_review_comment,
                         installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
..F
=================================== FAILURES ===================================
_______________ test_invalid_repo_config_no_review_on_non_opened _______________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f3623018f50>
mock_github_client = <MagicMock name='github_client' id='139870497272032'>

    @pytest.mark.asyncio
    async def test_invalid_repo_config_no_review_on_non_opened(webhook_handler, mock_github_client):
        """Test invalid config skips review comment for non-opened events."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["action"] = "labeled"
        mock_github_client.get_repo_file.return_value = 'chatops_required_permission = "invalid"'
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "error"
>       mock_github_client.create_pr_review_comment.assert_not_called()

tests/test_webhook_handler.py:741: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.create_pr_review_comment' id='139870497265648'>

    def assert_not_called(self):
        """assert that the mock was never called.
        """
        if self.call_count != 0:
            msg = ("Expected '%s' to not have been called. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'create_pr_review_comment' to not have been called. Called 1 times.
E           Calls: [call(12345, 'octocat/hello-world', 42, 'Stampbot configuration error in `stampbot.toml`:\n\nInvalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin\n\nPlease fix the file to re-enable automation.')].

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:947: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:47:59.626092Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:47:59.627292Z [warning  ] Invalid stampbot.toml in octocat/hello-world: Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning extra={'repo': 'octocat/hello-world', 'error': 'Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:47:59.626092Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:179 {'extra': {'repo': 'octocat/hello-world', 'error': 'Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin'}, 'event': 'Invalid stampbot.toml in octocat/hello-world: Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T05:47:59.627292Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_invalid_repo_config_no_review_on_non_opened - AssertionError: Expected 'create_pr_review_comment' to not have been called. Called 1 times.
Calls: [call(12345, 'octocat/hello-world', 42, 'Stampbot configuration error in `stampbot.toml`:\n\nInvalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin\n\nPlease fix the file to re-enable automation.')].
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 218 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 5, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -209,7 +209,7 @@
                     "message": "Invalid repository configuration",
                 }
 
-            if action == "opened":
+            if action <= "opened":
                 for label in repo_config.approval_labels:
                     label_exists = await run_in_threadpool(
                         github_client.repo_has_label,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 6, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -332,7 +332,7 @@
                     }
 
             # Check if we should remove approval when label is removed
-            if repo_config.auto_approve_on_label and action == "unlabeled":
+            if repo_config.auto_approve_on_label and action <= "unlabeled":
                 removed_label = payload.get("label", {}).get("name")
                 if removed_label in repo_config.approval_labels:
                     logger.info(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 7, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -418,7 +418,7 @@
             return True, False
 
         added_label = payload.get("label", {}).get("name")
-        if action == "labeled" and added_label in repo_config.approval_labels:
+        if action <= "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
         if action == "synchronize" and not repo_config.reapprove:
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 8, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -421,7 +421,7 @@
         if action == "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
-        if action == "synchronize" and not repo_config.reapprove:
+        if action <= "synchronize" and not repo_config.reapprove:
             return False, False
 
         if action not in ("labeled", "synchronize"):
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_with_approval_label_ignored __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fe20a9cd950>
mock_github_client = <MagicMock name='github_client' id='140608818871808'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_with_approval_label_ignored(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes do not re-approve just because an approval label exists."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "ignored"
        assert "no action" in result["message"].lower()
>       mock_github_client.find_bot_approval_reviews.assert_called_once()

tests/test_webhook_handler.py:144: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_approval_reviews' id='140608815533760'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:29:23.526921Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:29:23.527489Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:29:23.526921Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:29:23.527489Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_with_approval_label_ignored - AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 182 passed, 3 deselected, 1 warning in 2.73s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 9, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -474,7 +474,7 @@
                 continue
 
             review_commit = review.get("commit_id")
-            if not head_sha or not review_commit or review_commit == head_sha:
+            if not head_sha or not review_commit or review_commit <= head_sha:
                 return True
 
         return False
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 10, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -573,7 +573,7 @@
             command = command_match.group(1).lower()
             add_span_attributes(span, {"chatops.command": command})
 
-            if command == "help":
+            if command <= "help":
                 success = await self._post_help(
                     installation_id,
                     repo_full_name,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f7ca713abd0>
mock_github_client = <MagicMock name='github_client' id='140173358489552'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
>       assert "approved" in result["message"].lower()
E       AssertionError: assert 'approved' in 'help message posted'
E        +  where 'help message posted' = <built-in method lower of str object at 0x7f7ca73518b0>()
E        +    where <built-in method lower of str object at 0x7f7ca73518b0> = 'Help message posted'.lower

tests/test_webhook_handler.py:372: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:13:20.562027Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:13:20.562606Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:13:20.562027Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:13:20.562606Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'approved' in 'help message posted'
 +  where 'help message posted' = <built-in method lower of str object at 0x7f7ca73518b0>()
 +    where <built-in method lower of str object at 0x7f7ca73518b0> = 'Help message posted'.lower
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.72s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 11, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -724,7 +724,7 @@
 
                 org_repo_full_name = None
                 if (
-                    owner_type == "Organization"
+                    owner_type <= "Organization"
                     and owner_login
                     and repo_full_name != f"{owner_login}/.github"
                 ):
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 0, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -112,7 +112,7 @@
             )
 
             # Route to appropriate handler
-            if event_type == "pull_request":
+            if event_type > "pull_request":
                 result = await self._handle_pull_request(payload)
             elif event_type == "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
........................................................................ [ 30%]
........................................................................ [ 60%]
................................F
=================================== FAILURES ===================================
______________________________ test_unknown_event ______________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f31b7423ed0>

    @pytest.mark.asyncio
    async def test_unknown_event(webhook_handler):
        """Test handling unknown event type."""
        payload = {}
        result = await webhook_handler.handle_event("unknown", payload)
>       assert result["status"] == "ignored"
E       AssertionError: assert 'error' == 'ignored'
E         
E         - ignored
E         + error

tests/test_webhook_handler.py:58: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:09:06.647620Z [info     ] Received unknown event         [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'unknown', 'action': ''}
2026-06-29T05:09:06.647809Z [warning  ] Missing required fields in PR event [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'unknown', 'action': ''}, 'event': 'Received unknown event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:09:06.647620Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:164 {'event': 'Missing required fields in PR event', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T05:09:06.647809Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_unknown_event - AssertionError: assert 'error' == 'ignored'
  
  - ignored
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 176 passed, 3 deselected, 1 warning in 2.64s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 1, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -114,7 +114,7 @@
             # Route to appropriate handler
             if event_type == "pull_request":
                 result = await self._handle_pull_request(payload)
-            elif event_type == "pull_request_review_comment":
+            elif event_type > "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
             elif event_type == "issue_comment":
                 # Issue comments can be on PRs too
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.........F
=================================== FAILURES ===================================
____________________ test_pull_request_review_comment_event ____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f03851d6f30>
mock_github_client = <MagicMock name='github_client' id='139653094203008'>

    @pytest.mark.asyncio
    async def test_pull_request_review_comment_event(webhook_handler, mock_github_client):
        """Test handling pull_request_review_comment event type."""
        payload = {
            "action": "created",
            "pull_request": {
                "number": 42,
            },
            "comment": {
                "body": "@stampbot approve",
                "user": {"login": "testuser"},
            },
            "repository": {
                "full_name": "owner/repo",
            },
            "installation": {"id": 12345},
        }
    
        result = await webhook_handler.handle_event("pull_request_review_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:842: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:35:13.597211Z [info     ] Received pull_request_review_comment event [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request_review_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request_review_comment', 'action': 'created'}, 'event': 'Received pull_request_review_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:35:13.597211Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pull_request_review_comment_event - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 225 passed, 3 deselected, 1 warning in 3.20s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 2, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -116,7 +116,7 @@
                 result = await self._handle_pull_request(payload)
             elif event_type == "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
-            elif event_type == "issue_comment":
+            elif event_type > "issue_comment":
                 # Issue comments can be on PRs too
                 if "pull_request" in payload.get("issue", {}):
                     result = await self._handle_pr_comment(payload)
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7f0427346cf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'ignored' == 'ok'
E         
E         - ok
E         + ignored

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:13:10.009693Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T04:13:10.010537Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:13:10.009693Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'ignored' == 'ok'
  
  - ok
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 3.47s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 3, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -122,7 +122,7 @@
                     result = await self._handle_pr_comment(payload)
                 else:
                     result = {"status": "ignored", "message": "Not a PR comment"}
-            elif event_type == "ping":
+            elif event_type > "ping":
                 result = {"status": "ok", "message": "pong"}
             else:
                 result = {"status": "ignored", "message": f"Event type {event_type} not handled"}
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7f9d62d76cf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'ignored' == 'ok'
E         
E         - ok
E         + ignored

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:38:48.578605Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T05:38:48.579488Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:38:48.578605Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'ignored' == 'ok'
  
  - ok
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.37s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 4, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -190,7 +190,7 @@
                     },
                 )
 
-                if action == "opened":
+                if action > "opened":
                     await run_in_threadpool(
                         github_client.create_pr_review_comment,
                         installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.F
=================================== FAILURES ===================================
____________________ test_invalid_repo_config_posts_review _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f631d9dc4d0>
mock_github_client = <MagicMock name='github_client' id='140063675227776'>

    @pytest.mark.asyncio
    async def test_invalid_repo_config_posts_review(webhook_handler, mock_github_client):
        """Test invalid repo config logs and posts a review comment."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        mock_github_client.get_repo_file.return_value = 'chatops_required_permission = "invalid"'
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "error"
        assert "invalid" in result["message"].lower()
>       mock_github_client.create_pr_review_comment.assert_called_once()

tests/test_webhook_handler.py:727: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.create_pr_review_comment' id='140063675220384'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'create_pr_review_comment' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:24:14.087440Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:24:14.088628Z [warning  ] Invalid stampbot.toml in octocat/hello-world: Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning extra={'repo': 'octocat/hello-world', 'error': 'Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:24:14.087440Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:179 {'extra': {'repo': 'octocat/hello-world', 'error': 'Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin'}, 'event': 'Invalid stampbot.toml in octocat/hello-world: Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T05:24:14.088628Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_invalid_repo_config_posts_review - AssertionError: Expected 'create_pr_review_comment' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 217 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 5, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -209,7 +209,7 @@
                     "message": "Invalid repository configuration",
                 }
 
-            if action == "opened":
+            if action > "opened":
                 for label in repo_config.approval_labels:
                     label_exists = await run_in_threadpool(
                         github_client.repo_has_label,
........................................................................ [ 30%]
........................................................................ [ 60%]
...................................F
=================================== FAILURES ===================================
__________________ test_pr_opened_missing_label_logs_warning ___________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f8310cc6e70>
mock_github_client = <MagicMock name='github_client' id='140200900603456'>

    @pytest.mark.asyncio
    async def test_pr_opened_missing_label_logs_warning(webhook_handler, mock_github_client):
        """Test missing approval label triggers label check."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        mock_github_client.repo_has_label.return_value = False
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
>       assert mock_github_client.repo_has_label.call_count == 2
E       AssertionError: assert 0 == 2
E        +  where 0 = <MagicMock name='github_client.repo_has_label' id='140200900606816'>.call_count
E        +    where <MagicMock name='github_client.repo_has_label' id='140200900606816'> = <MagicMock name='github_client' id='140200900603456'>.repo_has_label

tests/test_webhook_handler.py:104: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:33:29.379817Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:33:29.380383Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:33:29.380829Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:33:29.379817Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:33:29.380383Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:33:29.380829Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_missing_label_logs_warning - AssertionError: assert 0 == 2
 +  where 0 = <MagicMock name='github_client.repo_has_label' id='140200900606816'>.call_count
 +    where <MagicMock name='github_client.repo_has_label' id='140200900606816'> = <MagicMock name='github_client' id='140200900603456'>.repo_has_label
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 179 passed, 3 deselected, 1 warning in 2.65s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 6, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -332,7 +332,7 @@
                     }
 
             # Check if we should remove approval when label is removed
-            if repo_config.auto_approve_on_label and action == "unlabeled":
+            if repo_config.auto_approve_on_label and action > "unlabeled":
                 removed_label = payload.get("label", {}).get("name")
                 if removed_label in repo_config.approval_labels:
                     logger.info(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f8ded75d910>
mock_github_client = <MagicMock name='github_client' id='140247550199184'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:264: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:54:32.805729Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:54:32.806300Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:54:32.805729Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:54:32.806300Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 7, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -418,7 +418,7 @@
             return True, False
 
         added_label = payload.get("label", {}).get("name")
-        if action == "labeled" and added_label in repo_config.approval_labels:
+        if action > "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
         if action == "synchronize" and not repo_config.reapprove:
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................F
=================================== FAILURES ===================================
_________________________ test_pr_labeled_autoapprove __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fcd7bf95260>
mock_github_client = <MagicMock name='github_client' id='140520593545872'>

    @pytest.mark.asyncio
    async def test_pr_labeled_autoapprove(webhook_handler, mock_github_client):
        """Test adding autoapprove label triggers approval."""
        payload = load_fixture("pr_labeled_autoapprove")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:126: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:29:33.369023Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:29:33.369596Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:29:33.369023Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:29:33.369596Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_autoapprove - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 181 passed, 3 deselected, 1 warning in 2.66s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 8, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -421,7 +421,7 @@
         if action == "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
-        if action == "synchronize" and not repo_config.reapprove:
+        if action > "synchronize" and not repo_config.reapprove:
             return False, False
 
         if action not in ("labeled", "synchronize"):
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................F
=================================== FAILURES ===================================
____________________ test_pr_synchronize_reapprove_disabled ____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fa1b522bb60>
mock_github_client = <MagicMock name='github_client' id='140332502126608'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_disabled(webhook_handler, mock_github_client):
        """Test new commits do not re-approve by default."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "ignored"
        assert "no action" in result["message"].lower()
>       mock_github_client.find_bot_approval_reviews.assert_not_called()

tests/test_webhook_handler.py:178: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_approval_reviews' id='140332502130304'>

    def assert_not_called(self):
        """assert that the mock was never called.
        """
        if self.call_count != 0:
            msg = ("Expected '%s' to not have been called. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'find_bot_approval_reviews' to not have been called. Called 1 times.
E           Calls: [call(12345, 'octocat/hello-world', 42)].

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:947: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:24:23.804591Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
2026-06-29T05:24:23.805322Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:24:23.804591Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:24:23.805322Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_disabled - AssertionError: Expected 'find_bot_approval_reviews' to not have been called. Called 1 times.
Calls: [call(12345, 'octocat/hello-world', 42)].
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 184 passed, 3 deselected, 1 warning in 2.72s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 9, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -474,7 +474,7 @@
                 continue
 
             review_commit = review.get("commit_id")
-            if not head_sha or not review_commit or review_commit == head_sha:
+            if not head_sha or not review_commit or review_commit > head_sha:
                 return True
 
         return False
........................................................................ [ 30%]
........................................................................ [ 60%]
.........................................F
=================================== FAILURES ===================================
____________ test_pr_synchronize_reapprove_enabled_for_stale_review ____________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fe097305e50>
mock_github_client = <MagicMock name='github_client' id='140602581771536'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_enabled_for_stale_review(
        webhook_handler, mock_github_client
    ):
        """Test new commits re-approve when reapprove is enabled and prior approval is stale."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
        mock_github_client.get_repo_file.return_value = "reapprove = true"
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "APPROVED", "commit_id": "oldsha"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:197: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:18:36.713569Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:18:36.713569Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_enabled_for_stale_review - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 185 passed, 3 deselected, 1 warning in 2.65s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 10, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -573,7 +573,7 @@
             command = command_match.group(1).lower()
             add_span_attributes(span, {"chatops.command": command})
 
-            if command == "help":
+            if command > "help":
                 success = await self._post_help(
                     installation_id,
                     repo_full_name,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................F
=================================== FAILURES ===================================
_________________________ test_issue_comment_unapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f0534886330>
mock_github_client = <MagicMock name='github_client' id='139660333090192'>

    @pytest.mark.asyncio
    async def test_issue_comment_unapprove(webhook_handler, mock_github_client):
        """Test @stampbot unapprove command."""
        payload = load_fixture("issue_comment_unapprove")
        mock_github_client.find_bot_reviews.return_value = [111]
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
>       assert "dismissed" in result["message"].lower()
E       AssertionError: assert 'dismissed' in 'help message posted'
E        +  where 'help message posted' = <built-in method lower of str object at 0x7f0534c5a4b0>()
E        +    where <built-in method lower of str object at 0x7f0534c5a4b0> = 'Help message posted'.lower

tests/test_webhook_handler.py:421: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:47:45.790055Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:47:45.790630Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:47:45.790055Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:47:45.790630Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_unapprove - AssertionError: assert 'dismissed' in 'help message posted'
 +  where 'help message posted' = <built-in method lower of str object at 0x7f0534c5a4b0>()
 +    where <built-in method lower of str object at 0x7f0534c5a4b0> = 'Help message posted'.lower
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 200 passed, 3 deselected, 1 warning in 2.74s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 11, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -724,7 +724,7 @@
 
                 org_repo_full_name = None
                 if (
-                    owner_type == "Organization"
+                    owner_type > "Organization"
                     and owner_login
                     and repo_full_name != f"{owner_login}/.github"
                 ):
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................................F
=================================== FAILURES ===================================
_____________________ test_repo_config_uses_default_branch _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f5b9d788e90>
mock_github_client = <MagicMock name='github_client' id='140031459278928'>

    @pytest.mark.asyncio
    async def test_repo_config_uses_default_branch(webhook_handler, mock_github_client):
        """Test repo config is loaded from the default branch."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["repository"]["default_branch"] = "develop"
        payload["pull_request"]["base"]["ref"] = "release"
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        args = mock_github_client.get_repo_file.call_args[0]
>       assert args[3] == "develop"
E       AssertionError: assert None == 'develop'

tests/test_webhook_handler.py:643: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:52:02.240337Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:52:02.241046Z [info     ] No stampbot.toml found in octocat/hello-world or octocat/.github, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': 'octocat/.github'}
2026-06-29T04:52:02.241759Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:52:02.240337Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': 'octocat/.github'}, 'event': 'No stampbot.toml found in octocat/hello-world or octocat/.github, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:52:02.241046Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:52:02.241759Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_repo_config_uses_default_branch - AssertionError: assert None == 'develop'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 213 passed, 3 deselected, 1 warning in 3.21s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 0, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -112,7 +112,7 @@
             )
 
             # Route to appropriate handler
-            if event_type == "pull_request":
+            if event_type >= "pull_request":
                 result = await self._handle_pull_request(payload)
             elif event_type == "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
........................................................................ [ 30%]
........................................................................ [ 60%]
................................F
=================================== FAILURES ===================================
______________________________ test_unknown_event ______________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fcadb7c7ed0>

    @pytest.mark.asyncio
    async def test_unknown_event(webhook_handler):
        """Test handling unknown event type."""
        payload = {}
        result = await webhook_handler.handle_event("unknown", payload)
>       assert result["status"] == "ignored"
E       AssertionError: assert 'error' == 'ignored'
E         
E         - ignored
E         + error

tests/test_webhook_handler.py:58: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:43:35.456732Z [info     ] Received unknown event         [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'unknown', 'action': ''}
2026-06-29T04:43:35.456925Z [warning  ] Missing required fields in PR event [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'unknown', 'action': ''}, 'event': 'Received unknown event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:43:35.456732Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:164 {'event': 'Missing required fields in PR event', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T04:43:35.456925Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_unknown_event - AssertionError: assert 'error' == 'ignored'
  
  - ignored
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 176 passed, 3 deselected, 1 warning in 2.62s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 1, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -114,7 +114,7 @@
             # Route to appropriate handler
             if event_type == "pull_request":
                 result = await self._handle_pull_request(payload)
-            elif event_type == "pull_request_review_comment":
+            elif event_type >= "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
             elif event_type == "issue_comment":
                 # Issue comments can be on PRs too
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 2, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -116,7 +116,7 @@
                 result = await self._handle_pull_request(payload)
             elif event_type == "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
-            elif event_type == "issue_comment":
+            elif event_type >= "issue_comment":
                 # Issue comments can be on PRs too
                 if "pull_request" in payload.get("issue", {}):
                     result = await self._handle_pr_comment(payload)
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7f3328a86cf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'ignored' == 'ok'
E         
E         - ok
E         + ignored

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:35:27.430985Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T04:35:27.431871Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:35:27.430985Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'ignored' == 'ok'
  
  - ok
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.36s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 3, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -122,7 +122,7 @@
                     result = await self._handle_pr_comment(payload)
                 else:
                     result = {"status": "ignored", "message": "Not a PR comment"}
-            elif event_type == "ping":
+            elif event_type >= "ping":
                 result = {"status": "ok", "message": "pong"}
             else:
                 result = {"status": "ignored", "message": f"Event type {event_type} not handled"}
........................................................................ [ 30%]
........................................................................ [ 60%]
................................F
=================================== FAILURES ===================================
______________________________ test_unknown_event ______________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f40d4233ed0>

    @pytest.mark.asyncio
    async def test_unknown_event(webhook_handler):
        """Test handling unknown event type."""
        payload = {}
        result = await webhook_handler.handle_event("unknown", payload)
>       assert result["status"] == "ignored"
E       AssertionError: assert 'ok' == 'ignored'
E         
E         - ignored
E         + ok

tests/test_webhook_handler.py:58: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:37:56.642149Z [info     ] Received unknown event         [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'unknown', 'action': ''}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'unknown', 'action': ''}, 'event': 'Received unknown event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:37:56.642149Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_unknown_event - AssertionError: assert 'ok' == 'ignored'
  
  - ignored
  + ok
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 176 passed, 3 deselected, 1 warning in 2.64s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 4, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -190,7 +190,7 @@
                     },
                 )
 
-                if action == "opened":
+                if action >= "opened":
                     await run_in_threadpool(
                         github_client.create_pr_review_comment,
                         installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 5, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -209,7 +209,7 @@
                     "message": "Invalid repository configuration",
                 }
 
-            if action == "opened":
+            if action >= "opened":
                 for label in repo_config.approval_labels:
                     label_exists = await run_in_threadpool(
                         github_client.repo_has_label,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.27s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 6, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -332,7 +332,7 @@
                     }
 
             # Check if we should remove approval when label is removed
-            if repo_config.auto_approve_on_label and action == "unlabeled":
+            if repo_config.auto_approve_on_label and action >= "unlabeled":
                 removed_label = payload.get("label", {}).get("name")
                 if removed_label in repo_config.approval_labels:
                     logger.info(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 7, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -418,7 +418,7 @@
             return True, False
 
         added_label = payload.get("label", {}).get("name")
-        if action == "labeled" and added_label in repo_config.approval_labels:
+        if action >= "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
         if action == "synchronize" and not repo_config.reapprove:
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 8, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -421,7 +421,7 @@
         if action == "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
-        if action == "synchronize" and not repo_config.reapprove:
+        if action >= "synchronize" and not repo_config.reapprove:
             return False, False
 
         if action not in ("labeled", "synchronize"):
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.29s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 9, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -474,7 +474,7 @@
                 continue
 
             review_commit = review.get("commit_id")
-            if not head_sha or not review_commit or review_commit == head_sha:
+            if not head_sha or not review_commit or review_commit >= head_sha:
                 return True
 
         return False
........................................................................ [ 30%]
........................................................................ [ 60%]
.........................................F
=================================== FAILURES ===================================
____________ test_pr_synchronize_reapprove_enabled_for_stale_review ____________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7ff6136e1e50>
mock_github_client = <MagicMock name='github_client' id='140694860522768'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_enabled_for_stale_review(
        webhook_handler, mock_github_client
    ):
        """Test new commits re-approve when reapprove is enabled and prior approval is stale."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
        mock_github_client.get_repo_file.return_value = "reapprove = true"
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "APPROVED", "commit_id": "oldsha"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:197: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:18:52.907927Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:18:52.907927Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_enabled_for_stale_review - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 185 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 10, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -573,7 +573,7 @@
             command = command_match.group(1).lower()
             add_span_attributes(span, {"chatops.command": command})
 
-            if command == "help":
+            if command >= "help":
                 success = await self._post_help(
                     installation_id,
                     repo_full_name,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................F
=================================== FAILURES ===================================
_________________________ test_issue_comment_unapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f036555a6f0>
mock_github_client = <MagicMock name='github_client' id='139652561913232'>

    @pytest.mark.asyncio
    async def test_issue_comment_unapprove(webhook_handler, mock_github_client):
        """Test @stampbot unapprove command."""
        payload = load_fixture("issue_comment_unapprove")
        mock_github_client.find_bot_reviews.return_value = [111]
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
>       assert "dismissed" in result["message"].lower()
E       AssertionError: assert 'dismissed' in 'help message posted'
E        +  where 'help message posted' = <built-in method lower of str object at 0x7f03659453b0>()
E        +    where <built-in method lower of str object at 0x7f03659453b0> = 'Help message posted'.lower

tests/test_webhook_handler.py:421: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:55:39.928481Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:55:39.929039Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:55:39.928481Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:55:39.929039Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_unapprove - AssertionError: assert 'dismissed' in 'help message posted'
 +  where 'help message posted' = <built-in method lower of str object at 0x7f03659453b0>()
 +    where <built-in method lower of str object at 0x7f03659453b0> = 'Help message posted'.lower
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 200 passed, 3 deselected, 1 warning in 2.72s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 11, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -724,7 +724,7 @@
 
                 org_repo_full_name = None
                 if (
-                    owner_type == "Organization"
+                    owner_type >= "Organization"
                     and owner_login
                     and repo_full_name != f"{owner_login}/.github"
                 ):
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................................F
=================================== FAILURES ===================================
_____________________ test_repo_config_uses_default_branch _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f6e123f2930>
mock_github_client = <MagicMock name='github_client' id='140110705393744'>

    @pytest.mark.asyncio
    async def test_repo_config_uses_default_branch(webhook_handler, mock_github_client):
        """Test repo config is loaded from the default branch."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["repository"]["default_branch"] = "develop"
        payload["pull_request"]["base"]["ref"] = "release"
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        args = mock_github_client.get_repo_file.call_args[0]
>       assert args[3] == "develop"
E       AssertionError: assert None == 'develop'

tests/test_webhook_handler.py:643: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:17:23.634520Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:17:23.635222Z [info     ] No stampbot.toml found in octocat/hello-world or octocat/.github, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': 'octocat/.github'}
2026-06-29T05:17:23.635915Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:17:23.634520Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': 'octocat/.github'}, 'event': 'No stampbot.toml found in octocat/hello-world or octocat/.github, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:17:23.635222Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:17:23.635915Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_repo_config_uses_default_branch - AssertionError: assert None == 'develop'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 213 passed, 3 deselected, 1 warning in 3.20s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 0, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -112,7 +112,7 @@
             )
 
             # Route to appropriate handler
-            if event_type == "pull_request":
+            if event_type is "pull_request":
                 result = await self._handle_pull_request(payload)
             elif event_type == "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:115: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    if event_type is "pull_request":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 2 warnings in 3.23s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 1, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -114,7 +114,7 @@
             # Route to appropriate handler
             if event_type == "pull_request":
                 result = await self._handle_pull_request(payload)
-            elif event_type == "pull_request_review_comment":
+            elif event_type is "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
             elif event_type == "issue_comment":
                 # Issue comments can be on PRs too
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:117: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    elif event_type is "pull_request_review_comment":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 2 warnings in 3.22s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 2, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -116,7 +116,7 @@
                 result = await self._handle_pull_request(payload)
             elif event_type == "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
-            elif event_type == "issue_comment":
+            elif event_type is "issue_comment":
                 # Issue comments can be on PRs too
                 if "pull_request" in payload.get("issue", {}):
                     result = await self._handle_pr_comment(payload)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:119: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    elif event_type is "issue_comment":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 2 warnings in 3.24s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 3, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -122,7 +122,7 @@
                     result = await self._handle_pr_comment(payload)
                 else:
                     result = {"status": "ignored", "message": "Not a PR comment"}
-            elif event_type == "ping":
+            elif event_type is "ping":
                 result = {"status": "ok", "message": "pong"}
             else:
                 result = {"status": "ignored", "message": f"Event type {event_type} not handled"}
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7fca7af4ecf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'ignored' == 'ok'
E         
E         - ok
E         + ignored

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:57:39.161460Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T04:57:39.162356Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:57:39.161460Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:125: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    elif event_type is "ping":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'ignored' == 'ok'
  
  - ok
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 2 warnings in 2.37s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 4, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -190,7 +190,7 @@
                     },
                 )
 
-                if action == "opened":
+                if action is "opened":
                     await run_in_threadpool(
                         github_client.create_pr_review_comment,
                         installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.F
=================================== FAILURES ===================================
____________________ test_invalid_repo_config_posts_review _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f268c2bae70>
mock_github_client = <MagicMock name='github_client' id='139803537235584'>

    @pytest.mark.asyncio
    async def test_invalid_repo_config_posts_review(webhook_handler, mock_github_client):
        """Test invalid repo config logs and posts a review comment."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        mock_github_client.get_repo_file.return_value = 'chatops_required_permission = "invalid"'
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "error"
        assert "invalid" in result["message"].lower()
>       mock_github_client.create_pr_review_comment.assert_called_once()

tests/test_webhook_handler.py:727: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.create_pr_review_comment' id='139803537228192'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'create_pr_review_comment' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:01:20.262518Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:01:20.263705Z [warning  ] Invalid stampbot.toml in octocat/hello-world: Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning extra={'repo': 'octocat/hello-world', 'error': 'Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:01:20.262518Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:179 {'extra': {'repo': 'octocat/hello-world', 'error': 'Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin'}, 'event': 'Invalid stampbot.toml in octocat/hello-world: Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T05:01:20.263705Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:193: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    if action is "opened":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_invalid_repo_config_posts_review - AssertionError: Expected 'create_pr_review_comment' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 217 passed, 3 deselected, 2 warnings in 3.26s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 5, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -209,7 +209,7 @@
                     "message": "Invalid repository configuration",
                 }
 
-            if action == "opened":
+            if action is "opened":
                 for label in repo_config.approval_labels:
                     label_exists = await run_in_threadpool(
                         github_client.repo_has_label,
........................................................................ [ 30%]
........................................................................ [ 60%]
...................................F
=================================== FAILURES ===================================
__________________ test_pr_opened_missing_label_logs_warning ___________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f04861e6e70>
mock_github_client = <MagicMock name='github_client' id='139657407966784'>

    @pytest.mark.asyncio
    async def test_pr_opened_missing_label_logs_warning(webhook_handler, mock_github_client):
        """Test missing approval label triggers label check."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        mock_github_client.repo_has_label.return_value = False
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
>       assert mock_github_client.repo_has_label.call_count == 2
E       AssertionError: assert 0 == 2
E        +  where 0 = <MagicMock name='github_client.repo_has_label' id='139657407970144'>.call_count
E        +    where <MagicMock name='github_client.repo_has_label' id='139657407970144'> = <MagicMock name='github_client' id='139657407966784'>.repo_has_label

tests/test_webhook_handler.py:104: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:29:51.428375Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:29:51.428927Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:29:51.429387Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:29:51.428375Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:29:51.428927Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:29:51.429387Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:212: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    if action is "opened":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_missing_label_logs_warning - AssertionError: assert 0 == 2
 +  where 0 = <MagicMock name='github_client.repo_has_label' id='139657407970144'>.call_count
 +    where <MagicMock name='github_client.repo_has_label' id='139657407970144'> = <MagicMock name='github_client' id='139657407966784'>.repo_has_label
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 179 passed, 3 deselected, 2 warnings in 2.65s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 6, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -332,7 +332,7 @@
                     }
 
             # Check if we should remove approval when label is removed
-            if repo_config.auto_approve_on_label and action == "unlabeled":
+            if repo_config.auto_approve_on_label and action is "unlabeled":
                 removed_label = payload.get("label", {}).get("name")
                 if removed_label in repo_config.approval_labels:
                     logger.info(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f527bd89910>
mock_github_client = <MagicMock name='github_client' id='139992240981392'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:264: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:39:38.815770Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:39:38.816344Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:39:38.815770Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:39:38.816344Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:335: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    if repo_config.auto_approve_on_label and action is "unlabeled":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 2 warnings in 2.69s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 7, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -418,7 +418,7 @@
             return True, False
 
         added_label = payload.get("label", {}).get("name")
-        if action == "labeled" and added_label in repo_config.approval_labels:
+        if action is "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
         if action == "synchronize" and not repo_config.reapprove:
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................F
=================================== FAILURES ===================================
_________________________ test_pr_labeled_autoapprove __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f77f9785260>
mock_github_client = <MagicMock name='github_client' id='140153264003728'>

    @pytest.mark.asyncio
    async def test_pr_labeled_autoapprove(webhook_handler, mock_github_client):
        """Test adding autoapprove label triggers approval."""
        payload = load_fixture("pr_labeled_autoapprove")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:126: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:16:38.272388Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:16:38.272941Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:16:38.272388Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:16:38.272941Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:421: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    if action is "labeled" and added_label in repo_config.approval_labels:

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_autoapprove - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 181 passed, 3 deselected, 2 warnings in 2.68s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 8, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -421,7 +421,7 @@
         if action == "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
-        if action == "synchronize" and not repo_config.reapprove:
+        if action is "synchronize" and not repo_config.reapprove:
             return False, False
 
         if action not in ("labeled", "synchronize"):
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:424: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    if action is "synchronize" and not repo_config.reapprove:

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 2 warnings in 3.26s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 9, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -474,7 +474,7 @@
                 continue
 
             review_commit = review.get("commit_id")
-            if not head_sha or not review_commit or review_commit == head_sha:
+            if not head_sha or not review_commit or review_commit is head_sha:
                 return True
 
         return False
........................................................................ [ 30%]
........................................................................ [ 60%]
..........................................F
=================================== FAILURES ===================================
_________ test_pr_synchronize_reapprove_enabled_current_review_ignored _________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f1aa145fe70>
mock_github_client = <MagicMock name='github_client' id='139752351036624'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_enabled_current_review_ignored(
        webhook_handler, mock_github_client
    ):
        """Test new commits do not re-approve when current head already has approval."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
        mock_github_client.get_repo_file.return_value = "reapprove = true"
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "APPROVED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:217: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:54:37.720622Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
2026-06-29T04:54:37.721676Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:54:37.720622Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:54:37.721676Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_enabled_current_review_ignored - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 186 passed, 3 deselected, 1 warning in 2.66s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 10, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -573,7 +573,7 @@
             command = command_match.group(1).lower()
             add_span_attributes(span, {"chatops.command": command})
 
-            if command == "help":
+            if command is "help":
                 success = await self._post_help(
                     installation_id,
                     repo_full_name,
........................................................................ [ 30%]
........................................................................ [ 60%]
............................................................F
=================================== FAILURES ===================================
_______________________ test_issue_comment_help_command ________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fc454c8ee70>
mock_github_client = <MagicMock name='github_client' id='140481212854160'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_command(webhook_handler, mock_github_client):
        """Test @stampbot help posts contextual help."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:473: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:34:16.546787Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:34:16.547356Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:34:16.546787Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:34:16.547356Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:576: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    if command is "help":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_command - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 204 passed, 3 deselected, 2 warnings in 2.76s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 11, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -724,7 +724,7 @@
 
                 org_repo_full_name = None
                 if (
-                    owner_type == "Organization"
+                    owner_type is "Organization"
                     and owner_login
                     and repo_full_name != f"{owner_login}/.github"
                 ):
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:727: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    owner_type is "Organization"

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 2 warnings in 3.24s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 0, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -112,7 +112,7 @@
             )
 
             # Route to appropriate handler
-            if event_type == "pull_request":
+            if event_type is not "pull_request":
                 result = await self._handle_pull_request(payload)
             elif event_type == "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7fb7dea12cf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'error' == 'ok'
E         
E         - ok
E         + error

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:44:26.522603Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T04:44:26.522844Z [warning  ] Missing required fields in PR event [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning client_ip=testclient
2026-06-29T04:44:26.523701Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:44:26.522603Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:164 {'event': 'Missing required fields in PR event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T04:44:26.522844Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:115: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    if event_type is not "pull_request":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'error' == 'ok'
  
  - ok
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 2 warnings in 2.37s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 1, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -114,7 +114,7 @@
             # Route to appropriate handler
             if event_type == "pull_request":
                 result = await self._handle_pull_request(payload)
-            elif event_type == "pull_request_review_comment":
+            elif event_type is not "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
             elif event_type == "issue_comment":
                 # Issue comments can be on PRs too
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7f3fae952cf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'ignored' == 'ok'
E         
E         - ok
E         + ignored

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:28:24.286624Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T05:28:24.287574Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:28:24.286624Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:117: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    elif event_type is not "pull_request_review_comment":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'ignored' == 'ok'
  
  - ok
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 2 warnings in 2.47s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 2, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -116,7 +116,7 @@
                 result = await self._handle_pull_request(payload)
             elif event_type == "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
-            elif event_type == "issue_comment":
+            elif event_type is not "issue_comment":
                 # Issue comments can be on PRs too
                 if "pull_request" in payload.get("issue", {}):
                     result = await self._handle_pr_comment(payload)
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7ff0f648ecf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'ignored' == 'ok'
E         
E         - ok
E         + ignored

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:39:43.469132Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T04:39:43.470022Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:39:43.469132Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:119: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    elif event_type is not "issue_comment":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'ignored' == 'ok'
  
  - ok
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 2 warnings in 2.39s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 3, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -122,7 +122,7 @@
                     result = await self._handle_pr_comment(payload)
                 else:
                     result = {"status": "ignored", "message": "Not a PR comment"}
-            elif event_type == "ping":
+            elif event_type is not "ping":
                 result = {"status": "ok", "message": "pong"}
             else:
                 result = {"status": "ignored", "message": f"Event type {event_type} not handled"}
........................................................................ [ 30%]
........................................................................ [ 60%]
...............................F
=================================== FAILURES ===================================
_______________________________ test_ping_event ________________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fb803980910>

    @pytest.mark.asyncio
    async def test_ping_event(webhook_handler):
        """Test handling ping event."""
        payload = {"zen": "Design for failure."}
        result = await webhook_handler.handle_event("ping", payload)
>       assert result["status"] == "ok"
E       AssertionError: assert 'ignored' == 'ok'
E         
E         - ok
E         + ignored

tests/test_webhook_handler.py:49: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:29:19.894381Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'ping', 'action': ''}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:29:19.894381Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:125: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    elif event_type is not "ping":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_ping_event - AssertionError: assert 'ignored' == 'ok'
  
  - ok
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 175 passed, 3 deselected, 2 warnings in 2.61s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 4, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -190,7 +190,7 @@
                     },
                 )
 
-                if action == "opened":
+                if action is not "opened":
                     await run_in_threadpool(
                         github_client.create_pr_review_comment,
                         installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
..F
=================================== FAILURES ===================================
_______________ test_invalid_repo_config_no_review_on_non_opened _______________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7feaf4e45190>
mock_github_client = <MagicMock name='github_client' id='140647111389408'>

    @pytest.mark.asyncio
    async def test_invalid_repo_config_no_review_on_non_opened(webhook_handler, mock_github_client):
        """Test invalid config skips review comment for non-opened events."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["action"] = "labeled"
        mock_github_client.get_repo_file.return_value = 'chatops_required_permission = "invalid"'
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "error"
>       mock_github_client.create_pr_review_comment.assert_not_called()

tests/test_webhook_handler.py:741: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.create_pr_review_comment' id='140647111383024'>

    def assert_not_called(self):
        """assert that the mock was never called.
        """
        if self.call_count != 0:
            msg = ("Expected '%s' to not have been called. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'create_pr_review_comment' to not have been called. Called 1 times.
E           Calls: [call(12345, 'octocat/hello-world', 42, 'Stampbot configuration error in `stampbot.toml`:\n\nInvalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin\n\nPlease fix the file to re-enable automation.')].

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:947: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:33:41.263122Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T04:33:41.264325Z [warning  ] Invalid stampbot.toml in octocat/hello-world: Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning extra={'repo': 'octocat/hello-world', 'error': 'Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:33:41.263122Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:179 {'extra': {'repo': 'octocat/hello-world', 'error': 'Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin'}, 'event': 'Invalid stampbot.toml in octocat/hello-world: Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T04:33:41.264325Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:193: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    if action is not "opened":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_invalid_repo_config_no_review_on_non_opened - AssertionError: Expected 'create_pr_review_comment' to not have been called. Called 1 times.
Calls: [call(12345, 'octocat/hello-world', 42, 'Stampbot configuration error in `stampbot.toml`:\n\nInvalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin\n\nPlease fix the file to re-enable automation.')].
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 218 passed, 3 deselected, 2 warnings in 3.23s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 5, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -209,7 +209,7 @@
                     "message": "Invalid repository configuration",
                 }
 
-            if action == "opened":
+            if action is not "opened":
                 for label in repo_config.approval_labels:
                     label_exists = await run_in_threadpool(
                         github_client.repo_has_label,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:212: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    if action is not "opened":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 2 warnings in 3.25s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 6, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -332,7 +332,7 @@
                     }
 
             # Check if we should remove approval when label is removed
-            if repo_config.auto_approve_on_label and action == "unlabeled":
+            if repo_config.auto_approve_on_label and action is not "unlabeled":
                 removed_label = payload.get("label", {}).get("name")
                 if removed_label in repo_config.approval_labels:
                     logger.info(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:335: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    if repo_config.auto_approve_on_label and action is not "unlabeled":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 2 warnings in 3.23s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 7, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -418,7 +418,7 @@
             return True, False
 
         added_label = payload.get("label", {}).get("name")
-        if action == "labeled" and added_label in repo_config.approval_labels:
+        if action is not "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
         if action == "synchronize" and not repo_config.reapprove:
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:421: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    if action is not "labeled" and added_label in repo_config.approval_labels:

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 2 warnings in 3.24s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 8, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -421,7 +421,7 @@
         if action == "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
-        if action == "synchronize" and not repo_config.reapprove:
+        if action is not "synchronize" and not repo_config.reapprove:
             return False, False
 
         if action not in ("labeled", "synchronize"):
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_with_approval_label_ignored __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f654abd9950>
mock_github_client = <MagicMock name='github_client' id='140073034235392'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_with_approval_label_ignored(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes do not re-approve just because an approval label exists."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "ignored"
        assert "no action" in result["message"].lower()
>       mock_github_client.find_bot_approval_reviews.assert_called_once()

tests/test_webhook_handler.py:144: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_approval_reviews' id='140073032044224'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:23:39.543256Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:23:39.543845Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:23:39.543256Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:23:39.543845Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:424: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    if action is not "synchronize" and not repo_config.reapprove:

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_with_approval_label_ignored - AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 182 passed, 3 deselected, 2 warnings in 2.70s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 9, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -474,7 +474,7 @@
                 continue
 
             review_commit = review.get("commit_id")
-            if not head_sha or not review_commit or review_commit == head_sha:
+            if not head_sha or not review_commit or review_commit is not head_sha:
                 return True
 
         return False
........................................................................ [ 30%]
........................................................................ [ 60%]
.........................................F
=================================== FAILURES ===================================
____________ test_pr_synchronize_reapprove_enabled_for_stale_review ____________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fecdbde6990>
mock_github_client = <MagicMock name='github_client' id='140655273567504'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_enabled_for_stale_review(
        webhook_handler, mock_github_client
    ):
        """Test new commits re-approve when reapprove is enabled and prior approval is stale."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
        mock_github_client.get_repo_file.return_value = "reapprove = true"
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "APPROVED", "commit_id": "oldsha"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:197: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:21:28.677270Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:21:28.677270Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_enabled_for_stale_review - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 185 passed, 3 deselected, 1 warning in 2.69s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 10, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -573,7 +573,7 @@
             command = command_match.group(1).lower()
             add_span_attributes(span, {"chatops.command": command})
 
-            if command == "help":
+            if command is not "help":
                 success = await self._post_help(
                     installation_id,
                     repo_full_name,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f31a97a1e50>
mock_github_client = <MagicMock name='github_client' id='139851274788816'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
>       assert "approved" in result["message"].lower()
E       AssertionError: assert 'approved' in 'help message posted'
E        +  where 'help message posted' = <built-in method lower of str object at 0x7f31a985aff0>()
E        +    where <built-in method lower of str object at 0x7f31a985aff0> = 'Help message posted'.lower

tests/test_webhook_handler.py:372: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:11:07.175070Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:11:07.175667Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:11:07.175070Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:11:07.175667Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:576: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    if command is not "help":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'approved' in 'help message posted'
 +  where 'help message posted' = <built-in method lower of str object at 0x7f31a985aff0>()
 +    where <built-in method lower of str object at 0x7f31a985aff0> = 'Help message posted'.lower
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 2 warnings in 2.71s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 11, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -724,7 +724,7 @@
 
                 org_repo_full_name = None
                 if (
-                    owner_type == "Organization"
+                    owner_type is not "Organization"
                     and owner_login
                     and repo_full_name != f"{owner_login}/.github"
                 ):
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................................F
=================================== FAILURES ===================================
_____________________ test_repo_config_uses_default_branch _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f76d2f0d910>
mock_github_client = <MagicMock name='github_client' id='140148322238544'>

    @pytest.mark.asyncio
    async def test_repo_config_uses_default_branch(webhook_handler, mock_github_client):
        """Test repo config is loaded from the default branch."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["repository"]["default_branch"] = "develop"
        payload["pull_request"]["base"]["ref"] = "release"
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        args = mock_github_client.get_repo_file.call_args[0]
>       assert args[3] == "develop"
E       AssertionError: assert None == 'develop'

tests/test_webhook_handler.py:643: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:46:04.532354Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:46:04.533035Z [info     ] No stampbot.toml found in octocat/hello-world or octocat/.github, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': 'octocat/.github'}
2026-06-29T05:46:04.533716Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:46:04.532354Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': 'octocat/.github'}, 'event': 'No stampbot.toml found in octocat/hello-world or octocat/.github, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:46:04.533035Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:46:04.533716Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:727: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    owner_type is not "Organization"

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_repo_config_uses_default_branch - AssertionError: assert None == 'develop'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 213 passed, 3 deselected, 2 warnings in 3.18s
operator: core/ReplaceComparisonOperator_NotEq_Eq, occurrence: 0, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -470,7 +470,7 @@
             GitHub did not provide enough commit information to prove staleness.
         """
         for review in reviews:
-            if review["state"] != "APPROVED":
+            if review["state"] == "APPROVED":
                 continue
 
             review_commit = review.get("commit_id")
........................................................................ [ 30%]
........................................................................ [ 60%]
.......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_reapproves_dismissed_review __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fdb8ded5750>
mock_github_client = <MagicMock name='github_client' id='140580953855312'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_reapproves_dismissed_review(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes re-approve when prior Stampbot approval was dismissed."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "DISMISSED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:162: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:40:54.833469Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:40:54.834027Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:40:54.833469Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:40:54.834027Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_reapproves_dismissed_review - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 183 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceComparisonOperator_NotEq_Eq, occurrence: 1, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -726,7 +726,7 @@
                 if (
                     owner_type == "Organization"
                     and owner_login
-                    and repo_full_name != f"{owner_login}/.github"
+                    and repo_full_name == f"{owner_login}/.github"
                 ):
                     org_repo_full_name = f"{owner_login}/.github"
                     org_content = await run_in_threadpool(
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................................................F
=================================== FAILURES ===================================
_____________________ test_org_github_repo_config_fallback _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f6c68a20f50>
mock_github_client = <MagicMock name='github_client' id='140103589262880'>

    @pytest.mark.asyncio
    async def test_org_github_repo_config_fallback(webhook_handler, mock_github_client):
        """Test org .github stampbot.toml is used when repo config is missing."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["repository"]["full_name"] = "acme/widgets"
        payload["repository"]["default_branch"] = "main"
        payload["repository"]["owner"] = {"login": "acme", "type": "Organization"}
        payload["pull_request"]["labels"] = [{"name": "org-approve"}]
    
        def get_repo_file_side_effect(_installation_id, repo_full_name, _file_path, _ref):
            if repo_full_name == "acme/widgets":
                return None
            if repo_full_name == "acme/.github":
                return 'approval_labels = ["org-approve"]'
            return None
    
        mock_github_client.get_repo_file.side_effect = get_repo_file_side_effect
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:666: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:15:56.701298Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:15:56.701861Z [info     ] No stampbot.toml found in acme/widgets, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'acme/widgets', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:15:56.701298Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'acme/widgets', 'org_repo': None}, 'event': 'No stampbot.toml found in acme/widgets, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:15:56.701861Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_org_github_repo_config_fallback - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 214 passed, 3 deselected, 1 warning in 3.19s
operator: core/ReplaceComparisonOperator_NotEq_Lt, occurrence: 0, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -470,7 +470,7 @@
             GitHub did not provide enough commit information to prove staleness.
         """
         for review in reviews:
-            if review["state"] != "APPROVED":
+            if review["state"] < "APPROVED":
                 continue
 
             review_commit = review.get("commit_id")
........................................................................ [ 30%]
........................................................................ [ 60%]
.......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_reapproves_dismissed_review __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7feb923ad750>
mock_github_client = <MagicMock name='github_client' id='140649747633488'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_reapproves_dismissed_review(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes re-approve when prior Stampbot approval was dismissed."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "DISMISSED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:162: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:24:57.994309Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:24:57.994857Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:24:57.994309Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:24:57.994857Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_reapproves_dismissed_review - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 183 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceComparisonOperator_NotEq_Lt, occurrence: 1, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -726,7 +726,7 @@
                 if (
                     owner_type == "Organization"
                     and owner_login
-                    and repo_full_name != f"{owner_login}/.github"
+                    and repo_full_name < f"{owner_login}/.github"
                 ):
                     org_repo_full_name = f"{owner_login}/.github"
                     org_content = await run_in_threadpool(
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................................................F
=================================== FAILURES ===================================
_____________________ test_org_github_repo_config_fallback _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7ff2ef018f50>
mock_github_client = <MagicMock name='github_client' id='140681369286176'>

    @pytest.mark.asyncio
    async def test_org_github_repo_config_fallback(webhook_handler, mock_github_client):
        """Test org .github stampbot.toml is used when repo config is missing."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["repository"]["full_name"] = "acme/widgets"
        payload["repository"]["default_branch"] = "main"
        payload["repository"]["owner"] = {"login": "acme", "type": "Organization"}
        payload["pull_request"]["labels"] = [{"name": "org-approve"}]
    
        def get_repo_file_side_effect(_installation_id, repo_full_name, _file_path, _ref):
            if repo_full_name == "acme/widgets":
                return None
            if repo_full_name == "acme/.github":
                return 'approval_labels = ["org-approve"]'
            return None
    
        mock_github_client.get_repo_file.side_effect = get_repo_file_side_effect
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:666: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:41:56.790554Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:41:56.791100Z [info     ] No stampbot.toml found in acme/widgets, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'acme/widgets', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:41:56.790554Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'acme/widgets', 'org_repo': None}, 'event': 'No stampbot.toml found in acme/widgets, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:41:56.791100Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_org_github_repo_config_fallback - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 214 passed, 3 deselected, 1 warning in 3.18s
operator: core/ReplaceComparisonOperator_NotEq_LtE, occurrence: 0, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -470,7 +470,7 @@
             GitHub did not provide enough commit information to prove staleness.
         """
         for review in reviews:
-            if review["state"] != "APPROVED":
+            if review["state"] <= "APPROVED":
                 continue
 
             review_commit = review.get("commit_id")
........................................................................ [ 30%]
........................................................................ [ 60%]
.......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_reapproves_dismissed_review __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f2ba0cd5850>
mock_github_client = <MagicMock name='github_client' id='139825356199248'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_reapproves_dismissed_review(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes re-approve when prior Stampbot approval was dismissed."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "DISMISSED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:162: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:20:21.916515Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:20:21.917074Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:20:21.916515Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:20:21.917074Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_reapproves_dismissed_review - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 183 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceComparisonOperator_NotEq_LtE, occurrence: 1, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -726,7 +726,7 @@
                 if (
                     owner_type == "Organization"
                     and owner_login
-                    and repo_full_name != f"{owner_login}/.github"
+                    and repo_full_name <= f"{owner_login}/.github"
                 ):
                     org_repo_full_name = f"{owner_login}/.github"
                     org_content = await run_in_threadpool(
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................................................F
=================================== FAILURES ===================================
_____________________ test_org_github_repo_config_fallback _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7ff56b825190>
mock_github_client = <MagicMock name='github_client' id='140692048033312'>

    @pytest.mark.asyncio
    async def test_org_github_repo_config_fallback(webhook_handler, mock_github_client):
        """Test org .github stampbot.toml is used when repo config is missing."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["repository"]["full_name"] = "acme/widgets"
        payload["repository"]["default_branch"] = "main"
        payload["repository"]["owner"] = {"login": "acme", "type": "Organization"}
        payload["pull_request"]["labels"] = [{"name": "org-approve"}]
    
        def get_repo_file_side_effect(_installation_id, repo_full_name, _file_path, _ref):
            if repo_full_name == "acme/widgets":
                return None
            if repo_full_name == "acme/.github":
                return 'approval_labels = ["org-approve"]'
            return None
    
        mock_github_client.get_repo_file.side_effect = get_repo_file_side_effect
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:666: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:58:04.113621Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:58:04.114197Z [info     ] No stampbot.toml found in acme/widgets, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'acme/widgets', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:58:04.113621Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'acme/widgets', 'org_repo': None}, 'event': 'No stampbot.toml found in acme/widgets, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:58:04.114197Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_org_github_repo_config_fallback - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 214 passed, 3 deselected, 1 warning in 3.19s
operator: core/ReplaceComparisonOperator_NotEq_Gt, occurrence: 0, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -470,7 +470,7 @@
             GitHub did not provide enough commit information to prove staleness.
         """
         for review in reviews:
-            if review["state"] != "APPROVED":
+            if review["state"] > "APPROVED":
                 continue
 
             review_commit = review.get("commit_id")
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_NotEq_Gt, occurrence: 1, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -726,7 +726,7 @@
                 if (
                     owner_type == "Organization"
                     and owner_login
-                    and repo_full_name != f"{owner_login}/.github"
+                    and repo_full_name > f"{owner_login}/.github"
                 ):
                     org_repo_full_name = f"{owner_login}/.github"
                     org_content = await run_in_threadpool(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceComparisonOperator_NotEq_GtE, occurrence: 0, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -470,7 +470,7 @@
             GitHub did not provide enough commit information to prove staleness.
         """
         for review in reviews:
-            if review["state"] != "APPROVED":
+            if review["state"] >= "APPROVED":
                 continue
 
             review_commit = review.get("commit_id")
........................................................................ [ 30%]
........................................................................ [ 60%]
..........................................F
=================================== FAILURES ===================================
_________ test_pr_synchronize_reapprove_enabled_current_review_ignored _________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fa25c28b150>
mock_github_client = <MagicMock name='github_client' id='140335236854992'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_enabled_current_review_ignored(
        webhook_handler, mock_github_client
    ):
        """Test new commits do not re-approve when current head already has approval."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
        mock_github_client.get_repo_file.return_value = "reapprove = true"
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "APPROVED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:217: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:44:36.038554Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
2026-06-29T04:44:36.039619Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:44:36.038554Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:44:36.039619Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_enabled_current_review_ignored - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 186 passed, 3 deselected, 1 warning in 2.66s
operator: core/ReplaceComparisonOperator_NotEq_GtE, occurrence: 1, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -726,7 +726,7 @@
                 if (
                     owner_type == "Organization"
                     and owner_login
-                    and repo_full_name != f"{owner_login}/.github"
+                    and repo_full_name >= f"{owner_login}/.github"
                 ):
                     org_repo_full_name = f"{owner_login}/.github"
                     org_content = await run_in_threadpool(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceComparisonOperator_NotEq_Is, occurrence: 0, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -470,7 +470,7 @@
             GitHub did not provide enough commit information to prove staleness.
         """
         for review in reviews:
-            if review["state"] != "APPROVED":
+            if review["state"] is "APPROVED":
                 continue
 
             review_commit = review.get("commit_id")
........................................................................ [ 30%]
........................................................................ [ 60%]
.......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_reapproves_dismissed_review __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f778b6d1750>
mock_github_client = <MagicMock name='github_client' id='140151417099600'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_reapproves_dismissed_review(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes re-approve when prior Stampbot approval was dismissed."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "DISMISSED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:162: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:51:49.516110Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T04:51:49.516675Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:51:49.516110Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:51:49.516675Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:473: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    if review["state"] is "APPROVED":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_reapproves_dismissed_review - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 183 passed, 3 deselected, 2 warnings in 2.66s
operator: core/ReplaceComparisonOperator_NotEq_Is, occurrence: 1, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -726,7 +726,7 @@
                 if (
                     owner_type == "Organization"
                     and owner_login
-                    and repo_full_name != f"{owner_login}/.github"
+                    and repo_full_name is f"{owner_login}/.github"
                 ):
                     org_repo_full_name = f"{owner_login}/.github"
                     org_content = await run_in_threadpool(
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................................................F
=================================== FAILURES ===================================
_____________________ test_org_github_repo_config_fallback _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f624a3a0f50>
mock_github_client = <MagicMock name='github_client' id='140060129457696'>

    @pytest.mark.asyncio
    async def test_org_github_repo_config_fallback(webhook_handler, mock_github_client):
        """Test org .github stampbot.toml is used when repo config is missing."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["repository"]["full_name"] = "acme/widgets"
        payload["repository"]["default_branch"] = "main"
        payload["repository"]["owner"] = {"login": "acme", "type": "Organization"}
        payload["pull_request"]["labels"] = [{"name": "org-approve"}]
    
        def get_repo_file_side_effect(_installation_id, repo_full_name, _file_path, _ref):
            if repo_full_name == "acme/widgets":
                return None
            if repo_full_name == "acme/.github":
                return 'approval_labels = ["org-approve"]'
            return None
    
        mock_github_client.get_repo_file.side_effect = get_repo_file_side_effect
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:666: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:59:37.975285Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:59:37.975830Z [info     ] No stampbot.toml found in acme/widgets, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'acme/widgets', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:59:37.975285Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'acme/widgets', 'org_repo': None}, 'event': 'No stampbot.toml found in acme/widgets, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:59:37.975830Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_org_github_repo_config_fallback - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 214 passed, 3 deselected, 1 warning in 3.18s
operator: core/ReplaceComparisonOperator_NotEq_IsNot, occurrence: 0, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -470,7 +470,7 @@
             GitHub did not provide enough commit information to prove staleness.
         """
         for review in reviews:
-            if review["state"] != "APPROVED":
+            if review["state"] is not "APPROVED":
                 continue
 
             review_commit = review.get("commit_id")
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/webhook_handler.py:473: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    if review["state"] is not "APPROVED":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 2 warnings in 3.23s
operator: core/ReplaceComparisonOperator_NotEq_IsNot, occurrence: 1, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -726,7 +726,7 @@
                 if (
                     owner_type == "Organization"
                     and owner_login
-                    and repo_full_name != f"{owner_login}/.github"
+                    and repo_full_name is not f"{owner_login}/.github"
                 ):
                     org_repo_full_name = f"{owner_login}/.github"
                     org_content = await run_in_threadpool(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Gt_Eq, occurrence: 0, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -492,7 +492,7 @@
         comment_body = comment.get("body", "")
 
         # Security: limit comment length to prevent DoS
-        if len(comment_body) > MAX_COMMENT_LENGTH:
+        if len(comment_body) == MAX_COMMENT_LENGTH:
             return {"status": "ignored", "message": "Comment too long"}
 
         comment_body = comment_body.lower().strip()
........................................................................ [ 30%]
........................................................................ [ 60%]
..........................................................F
=================================== FAILURES ===================================
_____________________ test_issue_comment_too_long_rejected _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fd09129be30>
mock_github_client = <MagicMock name='github_client' id='140533765480400'>

    @pytest.mark.asyncio
    async def test_issue_comment_too_long_rejected(webhook_handler, mock_github_client):
        """Test that comments exceeding max length are rejected to prevent DoS."""
        payload = load_fixture("issue_comment_approve")
        # Create an excessively long comment (> 64KB)
        payload["comment"]["body"] = "@stampbot approve " + "x" * 100000
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:446: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:14:21.270097Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:14:21.270745Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:14:21.270097Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:14:21.270745Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_too_long_rejected - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 202 passed, 3 deselected, 1 warning in 2.76s
operator: core/ReplaceComparisonOperator_Gt_NotEq, occurrence: 0, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -492,7 +492,7 @@
         comment_body = comment.get("body", "")
 
         # Security: limit comment length to prevent DoS
-        if len(comment_body) > MAX_COMMENT_LENGTH:
+        if len(comment_body) != MAX_COMMENT_LENGTH:
             return {"status": "ignored", "message": "Comment too long"}
 
         comment_body = comment_body.lower().strip()
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7ffbe4beaa50>
mock_github_client = <MagicMock name='github_client' id='140719852237024'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:30:56.631255Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:30:56.631255Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.73s
operator: core/ReplaceComparisonOperator_Gt_Lt, occurrence: 0, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -492,7 +492,7 @@
         comment_body = comment.get("body", "")
 
         # Security: limit comment length to prevent DoS
-        if len(comment_body) > MAX_COMMENT_LENGTH:
+        if len(comment_body) < MAX_COMMENT_LENGTH:
             return {"status": "ignored", "message": "Comment too long"}
 
         comment_body = comment_body.lower().strip()
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f12d7513cd0>
mock_github_client = <MagicMock name='github_client' id='139718827089872'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:45:14.564893Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:45:14.564893Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceComparisonOperator_Gt_LtE, occurrence: 0, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -492,7 +492,7 @@
         comment_body = comment.get("body", "")
 
         # Security: limit comment length to prevent DoS
-        if len(comment_body) > MAX_COMMENT_LENGTH:
+        if len(comment_body) <= MAX_COMMENT_LENGTH:
             return {"status": "ignored", "message": "Comment too long"}
 
         comment_body = comment_body.lower().strip()
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f43fa9eae50>
mock_github_client = <MagicMock name='github_client' id='139929945235408'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:45:56.206642Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:45:56.206642Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.71s
operator: core/ReplaceComparisonOperator_Gt_GtE, occurrence: 0, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -492,7 +492,7 @@
         comment_body = comment.get("body", "")
 
         # Security: limit comment length to prevent DoS
-        if len(comment_body) > MAX_COMMENT_LENGTH:
+        if len(comment_body) >= MAX_COMMENT_LENGTH:
             return {"status": "ignored", "message": "Comment too long"}
 
         comment_body = comment_body.lower().strip()
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceComparisonOperator_Gt_Is, occurrence: 0, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -492,7 +492,7 @@
         comment_body = comment.get("body", "")
 
         # Security: limit comment length to prevent DoS
-        if len(comment_body) > MAX_COMMENT_LENGTH:
+        if len(comment_body) is MAX_COMMENT_LENGTH:
             return {"status": "ignored", "message": "Comment too long"}
 
         comment_body = comment_body.lower().strip()
........................................................................ [ 30%]
........................................................................ [ 60%]
..........................................................F
=================================== FAILURES ===================================
_____________________ test_issue_comment_too_long_rejected _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f0d7988bdd0>
mock_github_client = <MagicMock name='github_client' id='139695850414032'>

    @pytest.mark.asyncio
    async def test_issue_comment_too_long_rejected(webhook_handler, mock_github_client):
        """Test that comments exceeding max length are rejected to prevent DoS."""
        payload = load_fixture("issue_comment_approve")
        # Create an excessively long comment (> 64KB)
        payload["comment"]["body"] = "@stampbot approve " + "x" * 100000
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:446: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:38:43.163273Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:38:43.163875Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:38:43.163273Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:38:43.163875Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_too_long_rejected - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 202 passed, 3 deselected, 1 warning in 2.73s
operator: core/ReplaceComparisonOperator_Gt_IsNot, occurrence: 0, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -492,7 +492,7 @@
         comment_body = comment.get("body", "")
 
         # Security: limit comment length to prevent DoS
-        if len(comment_body) > MAX_COMMENT_LENGTH:
+        if len(comment_body) is not MAX_COMMENT_LENGTH:
             return {"status": "ignored", "message": "Comment too long"}
 
         comment_body = comment_body.lower().strip()
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fa954ce7dd0>
mock_github_client = <MagicMock name='github_client' id='140365177561040'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:20:09.713170Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:20:09.713170Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceComparisonOperator_Is_Eq, occurrence: 0, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -217,7 +217,7 @@
                         repo_full_name,
                         label,
                     )
-                    if label_exists is False:
+                    if label_exists == False:
                         logger.warning(
                             "Approval label %s not found in %s",
                             label,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceComparisonOperator_Is_NotEq, occurrence: 0, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -217,7 +217,7 @@
                         repo_full_name,
                         label,
                     )
-                    if label_exists is False:
+                    if label_exists != False:
                         logger.warning(
                             "Approval label %s not found in %s",
                             label,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Is_Lt, occurrence: 0, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -217,7 +217,7 @@
                         repo_full_name,
                         label,
                     )
-                    if label_exists is False:
+                    if label_exists < False:
                         logger.warning(
                             "Approval label %s not found in %s",
                             label,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Is_LtE, occurrence: 0, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -217,7 +217,7 @@
                         repo_full_name,
                         label,
                     )
-                    if label_exists is False:
+                    if label_exists <= False:
                         logger.warning(
                             "Approval label %s not found in %s",
                             label,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Is_Gt, occurrence: 0, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -217,7 +217,7 @@
                         repo_full_name,
                         label,
                     )
-                    if label_exists is False:
+                    if label_exists > False:
                         logger.warning(
                             "Approval label %s not found in %s",
                             label,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceComparisonOperator_Is_GtE, occurrence: 0, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -217,7 +217,7 @@
                         repo_full_name,
                         label,
                     )
-                    if label_exists is False:
+                    if label_exists >= False:
                         logger.warning(
                             "Approval label %s not found in %s",
                             label,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceComparisonOperator_Is_IsNot, occurrence: 0, definition_name: webhook_secret
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -49,7 +49,7 @@
         Raises:
             RuntimeError: If webhook secret is not configured.
         """
-        if self._webhook_secret is None:
+        if self._webhook_secret is not None:
             if not settings.webhook_secret:
                 raise RuntimeError(
                     "Webhook secret not configured. Visit /setup to create your GitHub App."
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f16f5166250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:74: in verify_signature
    "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/hmac.py:218: in new
    return HMAC(key, msg, digestmod)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <hmac.HMAC object at 0x7f16f51c8270>, key = None
msg = b'{"test": "data"}', digestmod = <built-in function openssl_sha256>

    def __init__(self, key, msg=None, digestmod=''):
        """Create a new HMAC object.
    
        key: bytes or buffer, key for the keyed hash object.
        msg: bytes or buffer, Initial input for the hash or None.
        digestmod: A hash name suitable for hashlib.new(). *OR*
                   A hashlib constructor returning a new hash object. *OR*
                   A module supporting PEP 247.
    
                   Required as of 3.8, despite its position after the optional
                   msg argument.  Passing it as a keyword argument is
                   recommended, though not required for legacy API reasons.
        """
    
        if not isinstance(key, (bytes, bytearray)):
>           raise TypeError(f"key: expected bytes or bytearray, "
                            f"but got {type(key).__name__!r}")
E           TypeError: key: expected bytes or bytearray, but got 'NoneType'

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/hmac.py:71: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - TypeError: key: expected bytes or bytearray, but got 'NoneType'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.78s
operator: core/ReplaceComparisonOperator_Is_IsNot, occurrence: 1, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -217,7 +217,7 @@
                         repo_full_name,
                         label,
                     )
-                    if label_exists is False:
+                    if label_exists is not False:
                         logger.warning(
                             "Approval label %s not found in %s",
                             label,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceUnaryOperator_USub_UAdd, occurrence: 0, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -505,7 +505,7 @@
         if "pull_request" in payload.get("issue", {}):
             pr_url = payload["issue"]["pull_request"]["url"]
             # Extract PR number from URL
-            pr_number = int(pr_url.split("/")[-1])
+            pr_number = int(pr_url.split("/")[+1])
         elif "pull_request" in payload:
             pr_number = payload["pull_request"]["number"]
         else:
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fdf2493f150>
mock_github_client = <MagicMock name='github_client' id='140596382343120'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fdf2493f150>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
>           pr_number = int(pr_url.split("/")[+1])
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
E           ValueError: invalid literal for int() with base 10: ''

stampbot/webhook_handler.py:508: ValueError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:33:34.364080Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:33:34.364080Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - ValueError: invalid literal for int() with base 10: ''
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.77s
operator: core/ReplaceUnaryOperator_USub_Invert, occurrence: 0, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -505,7 +505,7 @@
         if "pull_request" in payload.get("issue", {}):
             pr_url = payload["issue"]["pull_request"]["url"]
             # Extract PR number from URL
-            pr_number = int(pr_url.split("/")[-1])
+            pr_number = int(pr_url.split("/")[~1])
         elif "pull_request" in payload:
             pr_number = payload["pull_request"]["number"]
         else:
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fb276de5cd0>
mock_github_client = <MagicMock name='github_client' id='140404405968848'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fb276de5cd0>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
>           pr_number = int(pr_url.split("/")[~1])
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
E           ValueError: invalid literal for int() with base 10: 'pulls'

stampbot/webhook_handler.py:508: ValueError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:34:56.572451Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:34:56.572451Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - ValueError: invalid literal for int() with base 10: 'pulls'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.76s
operator: core/ReplaceUnaryOperator_USub_Not, occurrence: 0, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -505,7 +505,7 @@
         if "pull_request" in payload.get("issue", {}):
             pr_url = payload["issue"]["pull_request"]["url"]
             # Extract PR number from URL
-            pr_number = int(pr_url.split("/")[-1])
+            pr_number = int(pr_url.split("/")[not 1])
         elif "pull_request" in payload:
             pr_number = payload["pull_request"]["number"]
         else:
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fa5ea249850>
mock_github_client = <MagicMock name='github_client' id='140350575194336'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fa5ea249850>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
>           pr_number = int(pr_url.split("/")[not 1])
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           ValueError: invalid literal for int() with base 10: 'https:'

stampbot/webhook_handler.py:508: ValueError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:45:51.870298Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:45:51.870298Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - ValueError: invalid literal for int() with base 10: 'https:'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.76s
operator: core/ReplaceUnaryOperator_Delete_USub, occurrence: 0, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -505,7 +505,7 @@
         if "pull_request" in payload.get("issue", {}):
             pr_url = payload["issue"]["pull_request"]["url"]
             # Extract PR number from URL
-            pr_number = int(pr_url.split("/")[-1])
+            pr_number = int(pr_url.split("/")[1])
         elif "pull_request" in payload:
             pr_number = payload["pull_request"]["number"]
         else:
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f670da241d0>
mock_github_client = <MagicMock name='github_client' id='140080518537168'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f670da241d0>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
>           pr_number = int(pr_url.split("/")[1])
                        ^^^^^^^^^^^^^^^^^^^^^^^^^
E           ValueError: invalid literal for int() with base 10: ''

stampbot/webhook_handler.py:508: ValueError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:30:22.844502Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:30:22.844502Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - ValueError: invalid literal for int() with base 10: ''
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.74s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 0, definition_name: webhook_secret
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -50,7 +50,7 @@
             RuntimeError: If webhook secret is not configured.
         """
         if self._webhook_secret is None:
-            if not settings.webhook_secret:
+            if  settings.webhook_secret:
                 raise RuntimeError(
                     "Webhook secret not configured. Visit /setup to create your GitHub App."
                 )
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7fd6fd67e250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:74: in verify_signature
    "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
                         ^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fd6fd8de270>

    @property
    def webhook_secret(self) -> bytes:
        """Get webhook secret, initializing if needed.
    
        Returns:
            Webhook secret as bytes.
    
        Raises:
            RuntimeError: If webhook secret is not configured.
        """
        if self._webhook_secret is None:
            if  settings.webhook_secret:
>               raise RuntimeError(
                    "Webhook secret not configured. Visit /setup to create your GitHub App."
                )
E               RuntimeError: Webhook secret not configured. Visit /setup to create your GitHub App.

stampbot/webhook_handler.py:54: RuntimeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - RuntimeError: Webhook secret not configured. Visit /setup to create your GitHub App.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 1, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -67,7 +67,7 @@
         Returns:
             True if signature is valid
         """
-        if not signature:
+        if  signature:
             return False
 
         expected_signature = (
........................................................................ [ 30%]
.......................................F
=================================== FAILURES ===================================
__________________________ test_webhook_invalid_json ___________________________

test_client = <starlette.testclient.TestClient object at 0x7f0b744969c0>

    def test_webhook_invalid_json(test_client: TestClient):
        """Test webhook rejects invalid JSON payload."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        # Create a valid signature for invalid JSON
        body = b"not valid json"
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
>       assert response.status_code == 400
E       assert 401 == 400
E        +  where 401 = <Response [401 Unauthorized]>.status_code

tests/test_main.py:187: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:50:15.899703Z [warning  ] Invalid webhook signature      [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=warning client_ip=testclient
2026-06-29T05:50:15.900498Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized" [httpx]
------------------------------ Captured log call -------------------------------
WARNING  stampbot.main:main.py:340 {'event': 'Invalid webhook signature', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'warning', 'timestamp': '2026-06-29T05:50:15.899703Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_invalid_json - assert 401 == 400
 +  where 401 = <Response [401 Unauthorized]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 111 passed, 3 deselected, 1 warning in 2.37s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 2, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -160,7 +160,7 @@
                 "github.action": action or "unknown",
             },
         ) as span:
-            if not all([pr_number, repo_full_name, installation_id]):
+            if  all([pr_number, repo_full_name, installation_id]):
                 logger.warning("Missing required fields in PR event")
                 add_span_attributes(span, {"webhook.result": "missing_fields"})
                 set_span_ok(span)
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fb2ab812ea0>
mock_github_client = <MagicMock name='github_client' id='140405359051168'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:73: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:24:53.031011Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:24:53.031206Z [warning  ] Missing required fields in PR event [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:24:53.031011Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:164 {'event': 'Missing required fields in PR event', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T05:24:53.031206Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.63s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 3, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -244,7 +244,7 @@
                         pr_number,
                         repo_config,
                     )
-                    if not should_approve:
+                    if  should_approve:
                         add_span_attributes(span, {"webhook.result": "no_action"})
                         set_span_ok(span)
                         return {"status": "ignored", "message": "No action needed"}
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f8954636ea0>
mock_github_client = <MagicMock name='github_client' id='140227813343648'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:73: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:16:23.339582Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:16:23.340302Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:16:23.339582Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:16:23.340302Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.64s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 4, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -267,7 +267,7 @@
                     is_eligible, reason = repo_config.is_pr_eligible(
                         labels, pr_title, pr_author, author_team_slugs
                     )
-                    if not is_eligible:
+                    if  is_eligible:
                         logger.info(
                             "PR #%d not eligible for auto-approval: %s",
                             pr_number,
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fb9a2c3eea0>
mock_github_client = <MagicMock name='github_client' id='140435275186592'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:73: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:07:41.401893Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:07:41.402649Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:07:41.403414Z [info     ] PR #42 not eligible for auto-approval: None [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'pr_author': 'contributor', 'reason': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:07:41.401893Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:07:41.402649Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:271 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'pr_author': 'contributor', 'reason': None}, 'event': 'PR #42 not eligible for auto-approval: None', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:07:41.403414Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.64s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 5, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -421,7 +421,7 @@
         if action == "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
-        if action == "synchronize" and not repo_config.reapprove:
+        if action == "synchronize" and  repo_config.reapprove:
             return False, False
 
         if action not in ("labeled", "synchronize"):
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................F
=================================== FAILURES ===================================
____________________ test_pr_synchronize_reapprove_disabled ____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f06b5b07b60>
mock_github_client = <MagicMock name='github_client' id='139666790600720'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_disabled(webhook_handler, mock_github_client):
        """Test new commits do not re-approve by default."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "ignored"
        assert "no action" in result["message"].lower()
>       mock_github_client.find_bot_approval_reviews.assert_not_called()

tests/test_webhook_handler.py:178: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_approval_reviews' id='139666790604416'>

    def assert_not_called(self):
        """assert that the mock was never called.
        """
        if self.call_count != 0:
            msg = ("Expected '%s' to not have been called. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'find_bot_approval_reviews' to not have been called. Called 1 times.
E           Calls: [call(12345, 'octocat/hello-world', 42)].

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:947: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:42:01.776200Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
2026-06-29T05:42:01.776946Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:42:01.776200Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:42:01.776946Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_disabled - AssertionError: Expected 'find_bot_approval_reviews' to not have been called. Called 1 times.
Calls: [call(12345, 'octocat/hello-world', 42)].
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 184 passed, 3 deselected, 1 warning in 2.74s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 6, definition_name: _approval_needs_refresh
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -449,7 +449,7 @@
         Returns:
             True when a prior approval exists but no active approval applies to the current head.
         """
-        if not reviews:
+        if  reviews:
             return False
 
         return not self._has_current_active_approval(reviews, head_sha)
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_with_approval_label_ignored __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f8ead9b1950>
mock_github_client = <MagicMock name='github_client' id='140250776190464'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_with_approval_label_ignored(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes do not re-approve just because an approval label exists."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:142: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:44:18.525125Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:44:18.525733Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:44:18.526350Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:44:18.525125Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:44:18.525733Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:44:18.526350Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_with_approval_label_ignored - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 182 passed, 3 deselected, 1 warning in 2.68s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 7, definition_name: _approval_needs_refresh
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -452,7 +452,7 @@
         if not reviews:
             return False
 
-        return not self._has_current_active_approval(reviews, head_sha)
+        return  self._has_current_active_approval(reviews, head_sha)
 
     def _has_current_active_approval(
         self,
........................................................................ [ 30%]
........................................................................ [ 60%]
.......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_reapproves_dismissed_review __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fb5f64d1750>
mock_github_client = <MagicMock name='github_client' id='140419496203600'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_reapproves_dismissed_review(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes re-approve when prior Stampbot approval was dismissed."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "DISMISSED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:162: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:11:28.280976Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:11:28.281571Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:11:28.280976Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:11:28.281571Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_reapproves_dismissed_review - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 183 passed, 3 deselected, 1 warning in 2.68s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 8, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -474,7 +474,7 @@
                 continue
 
             review_commit = review.get("commit_id")
-            if not head_sha or not review_commit or review_commit == head_sha:
+            if  head_sha or not review_commit or review_commit == head_sha:
                 return True
 
         return False
........................................................................ [ 30%]
........................................................................ [ 60%]
.........................................F
=================================== FAILURES ===================================
____________ test_pr_synchronize_reapprove_enabled_for_stale_review ____________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f554dee2990>
mock_github_client = <MagicMock name='github_client' id='140004352140560'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_enabled_for_stale_review(
        webhook_handler, mock_github_client
    ):
        """Test new commits re-approve when reapprove is enabled and prior approval is stale."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
        mock_github_client.get_repo_file.return_value = "reapprove = true"
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "APPROVED", "commit_id": "oldsha"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:197: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:29:18.580838Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:29:18.580838Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_enabled_for_stale_review - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 185 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 9, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -474,7 +474,7 @@
                 continue
 
             review_commit = review.get("commit_id")
-            if not head_sha or not review_commit or review_commit == head_sha:
+            if not head_sha or  review_commit or review_commit == head_sha:
                 return True
 
         return False
........................................................................ [ 30%]
........................................................................ [ 60%]
.........................................F
=================================== FAILURES ===================================
____________ test_pr_synchronize_reapprove_enabled_for_stale_review ____________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f5f106e3b60>
mock_github_client = <MagicMock name='github_client' id='140046270014736'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_enabled_for_stale_review(
        webhook_handler, mock_github_client
    ):
        """Test new commits re-approve when reapprove is enabled and prior approval is stale."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
        mock_github_client.get_repo_file.return_value = "reapprove = true"
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "APPROVED", "commit_id": "oldsha"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:197: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:49:49.385871Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:49:49.385871Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_enabled_for_stale_review - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 185 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 10, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -528,7 +528,7 @@
                 "chatops.commenter": commenter,
             },
         ) as span:
-            if not all([pr_number, repo_full_name, installation_id]):
+            if  all([pr_number, repo_full_name, installation_id]):
                 logger.warning("Missing required fields in comment event")
                 add_span_attributes(span, {"chatops.result": "missing_fields"})
                 set_span_ok(span)
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f7445d6e050>
mock_github_client = <MagicMock name='github_client' id='140137367248848'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:07:31.923738Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:07:31.923943Z [warning  ] Missing required fields in comment event [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:07:31.923738Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:532 {'event': 'Missing required fields in comment event', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T05:07:31.923943Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.72s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 11, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -557,7 +557,7 @@
                     "message": "Invalid repository configuration",
                 }
 
-            if not repo_config.chatops_enabled:
+            if  repo_config.chatops_enabled:
                 add_span_attributes(span, {"chatops.result": "disabled"})
                 set_span_ok(span)
                 return {"status": "ignored", "message": "Chatops not enabled"}
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7ff70074a9d0>
mock_github_client = <MagicMock name='github_client' id='140698844012496'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:42:39.269307Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:42:39.269897Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:42:39.269307Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:42:39.269897Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.71s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 12, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -564,7 +564,7 @@
 
             # Parse command
             command_match = re.search(r"@stampbot\s+(\w+)", comment_body)
-            if not command_match:
+            if  command_match:
                 chatops_commands_total.labels(command="none", status="ignored").inc()
                 add_span_attributes(span, {"chatops.result": "no_command"})
                 set_span_ok(span)
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f82574e7550>
mock_github_client = <MagicMock name='github_client' id='140197789294544'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:25:47.576690Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:25:47.577282Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:25:47.576690Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:25:47.577282Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.73s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 13, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -604,7 +604,7 @@
                     commenter,
                     repo_config.chatops_required_permission,
                 )
-                if not has_permission:
+                if  has_permission:
                     chatops_commands_total.labels(command=command, status="forbidden").inc()
                     add_span_attributes(
                         span,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f5cdded6dd0>
mock_github_client = <MagicMock name='github_client' id='140036837924816'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:45:06.119368Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:45:06.119933Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:45:06.119368Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:45:06.119933Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.71s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 14, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -935,7 +935,7 @@
                 "approval.trigger_type": trigger_type,
             },
         ) as span:
-            if not skip_existing_check:
+            if  skip_existing_check:
                 if head_sha:
                     existing_reviews = await run_in_threadpool(
                         github_client.find_bot_approval_reviews,
........................................................................ [ 30%]
........................................................................ [ 60%]
.......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_reapproves_dismissed_review __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f32ed2a1350>
mock_github_client = <MagicMock name='github_client' id='139856704312656'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_reapproves_dismissed_review(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes re-approve when prior Stampbot approval was dismissed."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "DISMISSED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        mock_github_client.approve_pr.assert_called_once()
>       mock_github_client.find_bot_reviews.assert_not_called()

tests/test_webhook_handler.py:164: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_reviews' id='139856705516752'>

    def assert_not_called(self):
        """assert that the mock was never called.
        """
        if self.call_count != 0:
            msg = ("Expected '%s' to not have been called. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'find_bot_reviews' to not have been called. Called 1 times.
E           Calls: [call(12345, 'octocat/hello-world', 42)].

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:947: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:38:39.152857Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:38:39.153418Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:38:39.153994Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:38:39.152857Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:38:39.153418Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:38:39.153994Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_reapproves_dismissed_review - AssertionError: Expected 'find_bot_reviews' to not have been called. Called 1 times.
Calls: [call(12345, 'octocat/hello-world', 42)].
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 183 passed, 3 deselected, 1 warning in 2.71s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 15, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -997,7 +997,7 @@
                 status=status,
             ).inc()
 
-            if not success:
+            if  success:
                 errors_total.labels(error_type="approval_failed").inc()
 
             add_span_attributes(span, {"approval.result": status})
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 16, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1046,7 +1046,7 @@
 
                 add_span_attributes(span, {"dismissal.reviews_found": len(review_ids)})
 
-                if not review_ids:
+                if  review_ids:
                     logger.info(
                         "No bot approvals found on PR #%d",
                         pr_number,
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f2c9955d910>
mock_github_client = <MagicMock name='github_client' id='139829526988176'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        assert "dismissed" in result["message"].lower()
        mock_github_client.find_bot_reviews.assert_called_once()
>       assert mock_github_client.dismiss_approval.call_count == 2
E       AssertionError: assert 0 == 2
E        +  where 0 = <MagicMock name='github_client.dismiss_approval' id='139829526989856'>.call_count
E        +    where <MagicMock name='github_client.dismiss_approval' id='139829526989856'> = <MagicMock name='github_client' id='139829526988176'>.dismiss_approval

tests/test_webhook_handler.py:267: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:21:17.366857Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:21:17.367450Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:21:17.367881Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T04:21:17.368324Z [info     ] No bot approvals found on PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:21:17.366857Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:21:17.367450Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:21:17.367881Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:1050 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42}, 'event': 'No bot approvals found on PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:21:17.368324Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 0 == 2
 +  where 0 = <MagicMock name='github_client.dismiss_approval' id='139829526989856'>.call_count
 +    where <MagicMock name='github_client.dismiss_approval' id='139829526989856'> = <MagicMock name='github_client' id='139829526988176'>.dismiss_approval
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.68s
operator: core/AddNot, occurrence: 0, definition_name: webhook_secret
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -49,7 +49,7 @@
         Raises:
             RuntimeError: If webhook secret is not configured.
         """
-        if self._webhook_secret is None:
+        if not self._webhook_secret is None:
             if not settings.webhook_secret:
                 raise RuntimeError(
                     "Webhook secret not configured. Visit /setup to create your GitHub App."
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f6f54e72250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:74: in verify_signature
    "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/hmac.py:218: in new
    return HMAC(key, msg, digestmod)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <hmac.HMAC object at 0x7f6f54ec4220>, key = None
msg = b'{"test": "data"}', digestmod = <built-in function openssl_sha256>

    def __init__(self, key, msg=None, digestmod=''):
        """Create a new HMAC object.
    
        key: bytes or buffer, key for the keyed hash object.
        msg: bytes or buffer, Initial input for the hash or None.
        digestmod: A hash name suitable for hashlib.new(). *OR*
                   A hashlib constructor returning a new hash object. *OR*
                   A module supporting PEP 247.
    
                   Required as of 3.8, despite its position after the optional
                   msg argument.  Passing it as a keyword argument is
                   recommended, though not required for legacy API reasons.
        """
    
        if not isinstance(key, (bytes, bytearray)):
>           raise TypeError(f"key: expected bytes or bytearray, "
                            f"but got {type(key).__name__!r}")
E           TypeError: key: expected bytes or bytearray, but got 'NoneType'

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/hmac.py:71: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - TypeError: key: expected bytes or bytearray, but got 'NoneType'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.71s
operator: core/AddNot, occurrence: 1, definition_name: webhook_secret
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -50,7 +50,7 @@
             RuntimeError: If webhook secret is not configured.
         """
         if self._webhook_secret is None:
-            if not settings.webhook_secret:
+            if not not settings.webhook_secret:
                 raise RuntimeError(
                     "Webhook secret not configured. Visit /setup to create your GitHub App."
                 )
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f6e48662250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:74: in verify_signature
    "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
                         ^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f6e488c2270>

    @property
    def webhook_secret(self) -> bytes:
        """Get webhook secret, initializing if needed.
    
        Returns:
            Webhook secret as bytes.
    
        Raises:
            RuntimeError: If webhook secret is not configured.
        """
        if self._webhook_secret is None:
            if not not settings.webhook_secret:
>               raise RuntimeError(
                    "Webhook secret not configured. Visit /setup to create your GitHub App."
                )
E               RuntimeError: Webhook secret not configured. Visit /setup to create your GitHub App.

stampbot/webhook_handler.py:54: RuntimeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - RuntimeError: Webhook secret not configured. Visit /setup to create your GitHub App.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.70s
operator: core/AddNot, occurrence: 2, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -67,7 +67,7 @@
         Returns:
             True if signature is valid
         """
-        if not signature:
+        if not not signature:
             return False
 
         expected_signature = (
........................................................................ [ 30%]
.......................................F
=================================== FAILURES ===================================
__________________________ test_webhook_invalid_json ___________________________

test_client = <starlette.testclient.TestClient object at 0x7f5130e7e9c0>

    def test_webhook_invalid_json(test_client: TestClient):
        """Test webhook rejects invalid JSON payload."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        # Create a valid signature for invalid JSON
        body = b"not valid json"
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
>       assert response.status_code == 400
E       assert 401 == 400
E        +  where 401 = <Response [401 Unauthorized]>.status_code

tests/test_main.py:187: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:30:31.876542Z [warning  ] Invalid webhook signature      [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=warning client_ip=testclient
2026-06-29T04:30:31.877345Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized" [httpx]
------------------------------ Captured log call -------------------------------
WARNING  stampbot.main:main.py:340 {'event': 'Invalid webhook signature', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'warning', 'timestamp': '2026-06-29T04:30:31.876542Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_invalid_json - assert 401 == 400
 +  where 401 = <Response [401 Unauthorized]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 111 passed, 3 deselected, 1 warning in 2.36s
operator: core/AddNot, occurrence: 3, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -112,7 +112,7 @@
             )
 
             # Route to appropriate handler
-            if event_type == "pull_request":
+            if not event_type == "pull_request":
                 result = await self._handle_pull_request(payload)
             elif event_type == "pull_request_review_comment":
                 result = await self._handle_pr_comment(payload)
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7f059418acf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ok"
E       AssertionError: assert 'error' == 'ok'
E         
E         - ok
E         + error

tests/test_main.py:219: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:45:38.074919Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T04:45:38.075149Z [warning  ] Missing required fields in PR event [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning client_ip=testclient
2026-06-29T04:45:38.075990Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:45:38.074919Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:164 {'event': 'Missing required fields in PR event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T04:45:38.075149Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - AssertionError: assert 'error' == 'ok'
  
  - ok
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.38s
operator: core/AddNot, occurrence: 4, definition_name: handle_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -118,7 +118,7 @@
                 result = await self._handle_pr_comment(payload)
             elif event_type == "issue_comment":
                 # Issue comments can be on PRs too
-                if "pull_request" in payload.get("issue", {}):
+                if not "pull_request" in payload.get("issue", {}):
                     result = await self._handle_pr_comment(payload)
                 else:
                     result = {"status": "ignored", "message": "Not a PR comment"}
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f9c83ac2f50>
mock_github_client = <MagicMock name='github_client' id='140310202933200'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:30:55.639253Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:30:55.639253Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.70s
operator: core/AddNot, occurrence: 5, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -160,7 +160,7 @@
                 "github.action": action or "unknown",
             },
         ) as span:
-            if not all([pr_number, repo_full_name, installation_id]):
+            if not not all([pr_number, repo_full_name, installation_id]):
                 logger.warning("Missing required fields in PR event")
                 add_span_attributes(span, {"webhook.result": "missing_fields"})
                 set_span_ok(span)
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f2676146ea0>
mock_github_client = <MagicMock name='github_client' id='139803165295008'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:73: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:50:20.718928Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:50:20.719123Z [warning  ] Missing required fields in PR event [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:50:20.718928Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:164 {'event': 'Missing required fields in PR event', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T05:50:20.719123Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.63s
operator: core/AddNot, occurrence: 6, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -175,7 +175,7 @@
                 owner_type,
             )
 
-            if repo_config.config_error:
+            if not repo_config.config_error:
                 logger.warning(
                     "Invalid stampbot.toml in %s: %s",
                     repo_full_name,
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fb275536ea0>
mock_github_client = <MagicMock name='github_client' id='140404448068000'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:73: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:18:18.527385Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:18:18.528088Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:18:18.528562Z [warning  ] Invalid stampbot.toml in octocat/hello-world: None [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning extra={'repo': 'octocat/hello-world', 'error': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:18:18.527385Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:18:18.528088Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:179 {'extra': {'repo': 'octocat/hello-world', 'error': None}, 'event': 'Invalid stampbot.toml in octocat/hello-world: None', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T04:18:18.528562Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.63s
operator: core/AddNot, occurrence: 7, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -190,7 +190,7 @@
                     },
                 )
 
-                if action == "opened":
+                if not action == "opened":
                     await run_in_threadpool(
                         github_client.create_pr_review_comment,
                         installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.F
=================================== FAILURES ===================================
____________________ test_invalid_repo_config_posts_review _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f81c20584d0>
mock_github_client = <MagicMock name='github_client' id='140195282509440'>

    @pytest.mark.asyncio
    async def test_invalid_repo_config_posts_review(webhook_handler, mock_github_client):
        """Test invalid repo config logs and posts a review comment."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        mock_github_client.get_repo_file.return_value = 'chatops_required_permission = "invalid"'
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "error"
        assert "invalid" in result["message"].lower()
>       mock_github_client.create_pr_review_comment.assert_called_once()

tests/test_webhook_handler.py:727: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.create_pr_review_comment' id='140195282502048'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'create_pr_review_comment' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:17:47.476953Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:17:47.478164Z [warning  ] Invalid stampbot.toml in octocat/hello-world: Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning extra={'repo': 'octocat/hello-world', 'error': 'Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:17:47.476953Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:179 {'extra': {'repo': 'octocat/hello-world', 'error': 'Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin'}, 'event': 'Invalid stampbot.toml in octocat/hello-world: Invalid chatops_required_permission: invalid. Valid values: none, read, triage, write, maintain, admin', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T05:17:47.478164Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_invalid_repo_config_posts_review - AssertionError: Expected 'create_pr_review_comment' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 217 passed, 3 deselected, 1 warning in 3.24s
operator: core/AddNot, occurrence: 8, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -209,7 +209,7 @@
                     "message": "Invalid repository configuration",
                 }
 
-            if action == "opened":
+            if not action == "opened":
                 for label in repo_config.approval_labels:
                     label_exists = await run_in_threadpool(
                         github_client.repo_has_label,
........................................................................ [ 30%]
........................................................................ [ 60%]
...................................F
=================================== FAILURES ===================================
__________________ test_pr_opened_missing_label_logs_warning ___________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f921daeae70>
mock_github_client = <MagicMock name='github_client' id='140265551752768'>

    @pytest.mark.asyncio
    async def test_pr_opened_missing_label_logs_warning(webhook_handler, mock_github_client):
        """Test missing approval label triggers label check."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        mock_github_client.repo_has_label.return_value = False
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
>       assert mock_github_client.repo_has_label.call_count == 2
E       AssertionError: assert 0 == 2
E        +  where 0 = <MagicMock name='github_client.repo_has_label' id='140265551756128'>.call_count
E        +    where <MagicMock name='github_client.repo_has_label' id='140265551756128'> = <MagicMock name='github_client' id='140265551752768'>.repo_has_label

tests/test_webhook_handler.py:104: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:42:48.683185Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:42:48.683778Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:42:48.684217Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:42:48.683185Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:42:48.683778Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:42:48.684217Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_missing_label_logs_warning - AssertionError: assert 0 == 2
 +  where 0 = <MagicMock name='github_client.repo_has_label' id='140265551756128'>.call_count
 +    where <MagicMock name='github_client.repo_has_label' id='140265551756128'> = <MagicMock name='github_client' id='140265551752768'>.repo_has_label
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 179 passed, 3 deselected, 1 warning in 2.65s
operator: core/AddNot, occurrence: 9, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -217,7 +217,7 @@
                         repo_full_name,
                         label,
                     )
-                    if label_exists is False:
+                    if not label_exists is False:
                         logger.warning(
                             "Approval label %s not found in %s",
                             label,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.29s
operator: core/AddNot, occurrence: 10, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -226,7 +226,7 @@
                         )
 
             # Check if we should approve based on labels
-            if repo_config.auto_approve_on_label and action in [
+            if not repo_config.auto_approve_on_label and action in [
                 "opened",
                 "reopened",
                 "labeled",
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fb92873aea0>
mock_github_client = <MagicMock name='github_client' id='140433234641312'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:73: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:42:25.620225Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:42:25.620973Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:42:25.620225Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:42:25.620973Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.63s
operator: core/AddNot, occurrence: 11, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -234,7 +234,7 @@
             ]:
                 labels = [label["name"] for label in pr.get("labels", [])]
                 approval_label = self._find_approval_label(labels, repo_config)
-                if approval_label:
+                if not approval_label:
                     should_approve, skip_existing_check = await self._should_approve_for_pr_event(
                         action,
                         payload,
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fcaca232ea0>
mock_github_client = <MagicMock name='github_client' id='140508961751456'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:73: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:29:46.546341Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:29:46.547117Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:29:46.546341Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:29:46.547117Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.62s
operator: core/AddNot, occurrence: 12, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -244,7 +244,7 @@
                         pr_number,
                         repo_config,
                     )
-                    if not should_approve:
+                    if not not should_approve:
                         add_span_attributes(span, {"webhook.result": "no_action"})
                         set_span_ok(span)
                         return {"status": "ignored", "message": "No action needed"}
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7ffbeb512ea0>
mock_github_client = <MagicMock name='github_client' id='140719962243488'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:73: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:03:39.023198Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:03:39.023942Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:03:39.023198Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:03:39.023942Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.65s
operator: core/AddNot, occurrence: 13, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -254,7 +254,7 @@
 
                     # Check if team membership verification is needed
                     author_team_slugs: list[str] | None = None
-                    if repo_config.needs_team_check(pr_author) and owner_login:
+                    if not repo_config.needs_team_check(pr_author) and owner_login:
                         author_team_slugs = await run_in_threadpool(
                             github_client.get_user_team_slugs,
                             installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
..................F
=================================== FAILURES ===================================
________________ test_pr_with_allowed_teams_triggers_team_check ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f0939c47590>
mock_github_client = <MagicMock name='github_client' id='139677599229536'>

    @pytest.mark.asyncio
    async def test_pr_with_allowed_teams_triggers_team_check(webhook_handler, mock_github_client):
        """Test PR with allowed_teams configured triggers team membership check."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        # Config with allowed_teams - user not in allowed_users so needs team check
        mock_github_client.get_repo_file.return_value = """
    allowed_teams = ["acme/release-team"]
    """
        # User is in the allowed team
        mock_github_client.get_user_team_slugs.return_value = ["release-team"]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:1028: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:22:01.669667Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:22:01.670842Z [info     ] PR #42 not eligible for auto-approval: PR author not a member of any allowed team [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'pr_author': 'contributor', 'reason': 'PR author not a member of any allowed team'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:22:01.669667Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:271 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'pr_author': 'contributor', 'reason': 'PR author not a member of any allowed team'}, 'event': 'PR #42 not eligible for auto-approval: PR author not a member of any allowed team', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:22:01.670842Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_with_allowed_teams_triggers_team_check - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 234 passed, 3 deselected, 1 warning in 3.25s
operator: core/AddNot, occurrence: 14, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -267,7 +267,7 @@
                     is_eligible, reason = repo_config.is_pr_eligible(
                         labels, pr_title, pr_author, author_team_slugs
                     )
-                    if not is_eligible:
+                    if not not is_eligible:
                         logger.info(
                             "PR #%d not eligible for auto-approval: %s",
                             pr_number,
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f36a0cbeea0>
mock_github_client = <MagicMock name='github_client' id='139872601424288'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:73: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:53:37.519753Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:53:37.520504Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:53:37.521339Z [info     ] PR #42 not eligible for auto-approval: None [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'pr_author': 'contributor', 'reason': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:53:37.519753Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:53:37.520504Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:271 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'pr_author': 'contributor', 'reason': None}, 'event': 'PR #42 not eligible for auto-approval: None', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:53:37.521339Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.64s
operator: core/AddNot, occurrence: 15, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -316,7 +316,7 @@
                     add_span_attributes(
                         span,
                         {
-                            "webhook.result": "approved" if success else "approval_failed",
+                            "webhook.result": "approved" if not success else "approval_failed",
                             "webhook.trigger_label": approval_label,
                         },
                     )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/AddNot, occurrence: 16, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -323,7 +323,7 @@
                     set_span_ok(span)
 
                     return {
-                        "status": "success" if success else "error",
+                        "status": "success" if not success else "error",
                         "message": (
                             f"PR approved via label: {approval_label}"
                             if success
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fa80e746ea0>
mock_github_client = <MagicMock name='github_client' id='140359772438944'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:73: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:36:55.647596Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:36:55.648343Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:36:55.649087Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:36:55.647596Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:36:55.648343Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:36:55.649087Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.63s
operator: core/AddNot, occurrence: 17, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -326,7 +326,7 @@
                         "status": "success" if success else "error",
                         "message": (
                             f"PR approved via label: {approval_label}"
-                            if success
+                            if not success
                             else "Failed to approve PR"
                         ),
                     }
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f55dd142ea0>
mock_github_client = <MagicMock name='github_client' id='140006756712864'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
>       assert "approved" in result["message"].lower()
E       AssertionError: assert 'approved' in 'failed to approve pr'
E        +  where 'failed to approve pr' = <built-in method lower of str object at 0x7f55dd4bfab0>()
E        +    where <built-in method lower of str object at 0x7f55dd4bfab0> = 'Failed to approve PR'.lower

tests/test_webhook_handler.py:74: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:28:09.304311Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:28:09.305098Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:28:09.305860Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:28:09.304311Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:28:09.305098Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:28:09.305860Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: assert 'approved' in 'failed to approve pr'
 +  where 'failed to approve pr' = <built-in method lower of str object at 0x7f55dd4bfab0>()
 +    where <built-in method lower of str object at 0x7f55dd4bfab0> = 'Failed to approve PR'.lower
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.75s
operator: core/AddNot, occurrence: 18, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -332,7 +332,7 @@
                     }
 
             # Check if we should remove approval when label is removed
-            if repo_config.auto_approve_on_label and action == "unlabeled":
+            if not repo_config.auto_approve_on_label and action == "unlabeled":
                 removed_label = payload.get("label", {}).get("name")
                 if removed_label in repo_config.approval_labels:
                     logger.info(
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fef22b95910>
mock_github_client = <MagicMock name='github_client' id='140665055643024'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:264: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:49:40.986622Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:49:40.987164Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:49:40.986622Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:49:40.987164Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.69s
operator: core/AddNot, occurrence: 19, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -334,7 +334,7 @@
             # Check if we should remove approval when label is removed
             if repo_config.auto_approve_on_label and action == "unlabeled":
                 removed_label = payload.get("label", {}).get("name")
-                if removed_label in repo_config.approval_labels:
+                if not removed_label in repo_config.approval_labels:
                     logger.info(
                         "Approval label %s removed from PR #%d",
                         removed_label,
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fb090d7d910>
mock_github_client = <MagicMock name='github_client' id='140396320195984'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:264: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:43:25.430428Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:43:25.430974Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:43:25.430428Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:43:25.430974Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.69s
operator: core/AddNot, occurrence: 20, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -358,7 +358,7 @@
                     add_span_attributes(
                         span,
                         {
-                            "webhook.result": "dismissed" if success else "dismiss_failed",
+                            "webhook.result": "dismissed" if not success else "dismiss_failed",
                             "webhook.removed_label": removed_label,
                         },
                     )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/AddNot, occurrence: 21, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -365,7 +365,7 @@
                     set_span_ok(span)
 
                     return {
-                        "status": "success" if success else "error",
+                        "status": "success" if not success else "error",
                         "message": (
                             "Approvals dismissed" if success else "Failed to dismiss approvals"
                         ),
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f4238d89910>
mock_github_client = <MagicMock name='github_client' id='139922397447568'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:264: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:37:10.428358Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:37:10.428918Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:37:10.429364Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:37:10.428358Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:37:10.428918Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:37:10.429364Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.70s
operator: core/AddNot, occurrence: 22, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -367,7 +367,7 @@
                     return {
                         "status": "success" if success else "error",
                         "message": (
-                            "Approvals dismissed" if success else "Failed to dismiss approvals"
+                            "Approvals dismissed" if not success else "Failed to dismiss approvals"
                         ),
                     }
 
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fe4f0d6d910>
mock_github_client = <MagicMock name='github_client' id='140621280576912'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
>       assert "dismissed" in result["message"].lower()
E       AssertionError: assert 'dismissed' in 'failed to dismiss approvals'
E        +  where 'failed to dismiss approvals' = <built-in method lower of str object at 0x7fe4f1bf6b00>()
E        +    where <built-in method lower of str object at 0x7fe4f1bf6b00> = 'Failed to dismiss approvals'.lower

tests/test_webhook_handler.py:265: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:44:38.229888Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:44:38.230490Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:44:38.230919Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:44:38.229888Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:44:38.230490Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:44:38.230919Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 'dismissed' in 'failed to dismiss approvals'
 +  where 'failed to dismiss approvals' = <built-in method lower of str object at 0x7fe4f1bf6b00>()
 +    where <built-in method lower of str object at 0x7fe4f1bf6b00> = 'Failed to dismiss approvals'.lower
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.68s
operator: core/AddNot, occurrence: 23, definition_name: _find_approval_label
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -386,7 +386,7 @@
             Matching approval label, if present.
         """
         for label in labels:
-            if label in repo_config.approval_labels:
+            if not label in repo_config.approval_labels:
                 return label
         return None
 
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fca4a556ea0>
mock_github_client = <MagicMock name='github_client' id='140506805928352'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:73: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:09:39.346659Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:09:39.347398Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:09:39.346659Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:09:39.347398Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.63s
operator: core/AddNot, occurrence: 24, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -414,7 +414,7 @@
         Returns:
             Tuple of (should approve, skip existing approval check).
         """
-        if action in ("opened", "reopened"):
+        if not action in ("opened", "reopened"):
             return True, False
 
         added_label = payload.get("label", {}).get("name")
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f0265756ea0>
mock_github_client = <MagicMock name='github_client' id='139648267551136'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:73: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:53:17.192786Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:53:17.193541Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:53:17.192786Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:53:17.193541Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.64s
operator: core/AddNot, occurrence: 25, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -418,7 +418,7 @@
             return True, False
 
         added_label = payload.get("label", {}).get("name")
-        if action == "labeled" and added_label in repo_config.approval_labels:
+        if not action == "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
         if action == "synchronize" and not repo_config.reapprove:
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................F
=================================== FAILURES ===================================
_________________________ test_pr_labeled_autoapprove __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f9a4d48d260>
mock_github_client = <MagicMock name='github_client' id='140300699064976'>

    @pytest.mark.asyncio
    async def test_pr_labeled_autoapprove(webhook_handler, mock_github_client):
        """Test adding autoapprove label triggers approval."""
        payload = load_fixture("pr_labeled_autoapprove")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:126: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:23:24.267687Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:23:24.268274Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:23:24.267687Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:23:24.268274Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_autoapprove - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 181 passed, 3 deselected, 1 warning in 2.66s
operator: core/AddNot, occurrence: 26, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -421,7 +421,7 @@
         if action == "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
-        if action == "synchronize" and not repo_config.reapprove:
+        if not action == "synchronize" and not repo_config.reapprove:
             return False, False
 
         if action not in ("labeled", "synchronize"):
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_with_approval_label_ignored __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fadfa7d9950>
mock_github_client = <MagicMock name='github_client' id='140385210088960'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_with_approval_label_ignored(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes do not re-approve just because an approval label exists."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "ignored"
        assert "no action" in result["message"].lower()
>       mock_github_client.find_bot_approval_reviews.assert_called_once()

tests/test_webhook_handler.py:144: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_approval_reviews' id='140385206750912'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:21:07.486203Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T04:21:07.486805Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:21:07.486203Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:21:07.486805Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_with_approval_label_ignored - AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 182 passed, 3 deselected, 1 warning in 2.71s
operator: core/AddNot, occurrence: 27, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -424,7 +424,7 @@
         if action == "synchronize" and not repo_config.reapprove:
             return False, False
 
-        if action not in ("labeled", "synchronize"):
+        if not action not in ("labeled", "synchronize"):
             return False, False
 
         reviews = await run_in_threadpool(
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_with_approval_label_ignored __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f322eea9950>
mock_github_client = <MagicMock name='github_client' id='139853513702912'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_with_approval_label_ignored(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes do not re-approve just because an approval label exists."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "ignored"
        assert "no action" in result["message"].lower()
>       mock_github_client.find_bot_approval_reviews.assert_called_once()

tests/test_webhook_handler.py:144: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_approval_reviews' id='139853512380096'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:43:12.748583Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:43:12.749131Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:43:12.748583Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:43:12.749131Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_with_approval_label_ignored - AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 182 passed, 3 deselected, 1 warning in 2.73s
operator: core/AddNot, occurrence: 28, definition_name: _approval_needs_refresh
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -449,7 +449,7 @@
         Returns:
             True when a prior approval exists but no active approval applies to the current head.
         """
-        if not reviews:
+        if not not reviews:
             return False
 
         return not self._has_current_active_approval(reviews, head_sha)
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_with_approval_label_ignored __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f50f67d5950>
mock_github_client = <MagicMock name='github_client' id='139985711005184'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_with_approval_label_ignored(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes do not re-approve just because an approval label exists."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:142: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:05:32.363824Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:05:32.364408Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:05:32.364989Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:05:32.363824Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:05:32.364408Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:05:32.364989Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_with_approval_label_ignored - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 182 passed, 3 deselected, 1 warning in 2.67s
operator: core/AddNot, occurrence: 29, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -470,7 +470,7 @@
             GitHub did not provide enough commit information to prove staleness.
         """
         for review in reviews:
-            if review["state"] != "APPROVED":
+            if not review["state"] != "APPROVED":
                 continue
 
             review_commit = review.get("commit_id")
........................................................................ [ 30%]
........................................................................ [ 60%]
.......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_reapproves_dismissed_review __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f7f26dcd250>
mock_github_client = <MagicMock name='github_client' id='140184087729488'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_reapproves_dismissed_review(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes re-approve when prior Stampbot approval was dismissed."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "DISMISSED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:162: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:16:26.903049Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T04:16:26.903638Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:16:26.903049Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:16:26.903638Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_reapproves_dismissed_review - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 183 passed, 3 deselected, 1 warning in 2.66s
operator: core/AddNot, occurrence: 30, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -474,7 +474,7 @@
                 continue
 
             review_commit = review.get("commit_id")
-            if not head_sha or not review_commit or review_commit == head_sha:
+            if not not head_sha or not review_commit or review_commit == head_sha:
                 return True
 
         return False
........................................................................ [ 30%]
........................................................................ [ 60%]
.........................................F
=================================== FAILURES ===================================
____________ test_pr_synchronize_reapprove_enabled_for_stale_review ____________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f0e35afbb60>
mock_github_client = <MagicMock name='github_client' id='139699001763088'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_enabled_for_stale_review(
        webhook_handler, mock_github_client
    ):
        """Test new commits re-approve when reapprove is enabled and prior approval is stale."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
        mock_github_client.get_repo_file.return_value = "reapprove = true"
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "APPROVED", "commit_id": "oldsha"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:197: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:02:09.717270Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:02:09.717270Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_enabled_for_stale_review - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 185 passed, 3 deselected, 1 warning in 2.70s
operator: core/AddNot, occurrence: 31, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -492,7 +492,7 @@
         comment_body = comment.get("body", "")
 
         # Security: limit comment length to prevent DoS
-        if len(comment_body) > MAX_COMMENT_LENGTH:
+        if not len(comment_body) > MAX_COMMENT_LENGTH:
             return {"status": "ignored", "message": "Comment too long"}
 
         comment_body = comment_body.lower().strip()
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f5ea0c11c50>
mock_github_client = <MagicMock name='github_client' id='140044401385424'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:36:48.598930Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:36:48.598930Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.72s
operator: core/AddNot, occurrence: 32, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -498,7 +498,7 @@
         comment_body = comment_body.lower().strip()
 
         # Check if bot is mentioned
-        if "@stampbot" not in comment_body:
+        if not "@stampbot" not in comment_body:
             return {"status": "ignored", "message": "Bot not mentioned"}
 
         # Extract PR info
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f49eed99d50>
mock_github_client = <MagicMock name='github_client' id='139955517878496'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:00:11.862656Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:00:11.862656Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.71s
operator: core/AddNot, occurrence: 33, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -502,7 +502,7 @@
             return {"status": "ignored", "message": "Bot not mentioned"}
 
         # Extract PR info
-        if "pull_request" in payload.get("issue", {}):
+        if not "pull_request" in payload.get("issue", {}):
             pr_url = payload["issue"]["pull_request"]["url"]
             # Extract PR number from URL
             pr_number = int(pr_url.split("/")[-1])
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f6f0a253950>
mock_github_client = <MagicMock name='github_client' id='140114892054480'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:21:46.267956Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:21:46.267956Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.72s
operator: core/AddNot, occurrence: 34, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -528,7 +528,7 @@
                 "chatops.commenter": commenter,
             },
         ) as span:
-            if not all([pr_number, repo_full_name, installation_id]):
+            if not not all([pr_number, repo_full_name, installation_id]):
                 logger.warning("Missing required fields in comment event")
                 add_span_attributes(span, {"chatops.result": "missing_fields"})
                 set_span_ok(span)
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f21a4a242d0>
mock_github_client = <MagicMock name='github_client' id='139782404300752'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:08:19.865066Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:08:19.865292Z [warning  ] Missing required fields in comment event [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:08:19.865066Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:532 {'event': 'Missing required fields in comment event', 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T05:08:19.865292Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.72s
operator: core/AddNot, occurrence: 35, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -543,7 +543,7 @@
                 owner_type,
             )
 
-            if repo_config.config_error:
+            if not repo_config.config_error:
                 add_span_attributes(
                     span,
                     {
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f85a8f43950>
mock_github_client = <MagicMock name='github_client' id='140212056186832'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:51:14.832300Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:51:14.832866Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:51:14.832300Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:51:14.832866Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.71s
operator: core/AddNot, occurrence: 36, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -557,7 +557,7 @@
                     "message": "Invalid repository configuration",
                 }
 
-            if not repo_config.chatops_enabled:
+            if not not repo_config.chatops_enabled:
                 add_span_attributes(span, {"chatops.result": "disabled"})
                 set_span_ok(span)
                 return {"status": "ignored", "message": "Chatops not enabled"}
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f70b7c23cd0>
mock_github_client = <MagicMock name='github_client' id='140122022195424'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:47:27.200605Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:47:27.201175Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:47:27.200605Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:47:27.201175Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.71s
operator: core/AddNot, occurrence: 37, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -564,7 +564,7 @@
 
             # Parse command
             command_match = re.search(r"@stampbot\s+(\w+)", comment_body)
-            if not command_match:
+            if not not command_match:
                 chatops_commands_total.labels(command="none", status="ignored").inc()
                 add_span_attributes(span, {"chatops.result": "no_command"})
                 set_span_ok(span)
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f76becc1c50>
mock_github_client = <MagicMock name='github_client' id='140147914825680'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:33:44.924836Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:33:44.925418Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:33:44.924836Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:33:44.925418Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.72s
operator: core/AddNot, occurrence: 38, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -573,7 +573,7 @@
             command = command_match.group(1).lower()
             add_span_attributes(span, {"chatops.command": command})
 
-            if command == "help":
+            if not command == "help":
                 success = await self._post_help(
                     installation_id,
                     repo_full_name,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f1bbcca1dd0>
mock_github_client = <MagicMock name='github_client' id='139757109501904'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
>       assert "approved" in result["message"].lower()
E       AssertionError: assert 'approved' in 'help message posted'
E        +  where 'help message posted' = <built-in method lower of str object at 0x7f1bbcd55930>()
E        +    where <built-in method lower of str object at 0x7f1bbcd55930> = 'Help message posted'.lower

tests/test_webhook_handler.py:372: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:32:52.978381Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:32:52.978941Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:32:52.978381Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:32:52.978941Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'approved' in 'help message posted'
 +  where 'help message posted' = <built-in method lower of str object at 0x7f1bbcd55930>()
 +    where <built-in method lower of str object at 0x7f1bbcd55930> = 'Help message posted'.lower
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.70s
operator: core/AddNot, occurrence: 39, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -583,7 +583,7 @@
 
                 chatops_commands_total.labels(
                     command="help",
-                    status="success" if success else "failure",
+                    status="success" if not success else "failure",
                 ).inc()
 
                 add_span_attributes(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/AddNot, occurrence: 40, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -587,7 +587,7 @@
                 ).inc()
 
                 add_span_attributes(
-                    span, {"chatops.result": "help_posted" if success else "help_failed"}
+                    span, {"chatops.result": "help_posted" if not success else "help_failed"}
                 )
                 set_span_ok(span)
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/AddNot, occurrence: 41, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -592,7 +592,7 @@
                 set_span_ok(span)
 
                 return {
-                    "status": "success" if success else "error",
+                    "status": "success" if not success else "error",
                     "message": "Help message posted" if success else "Failed to post help message",
                 }
 
........................................................................ [ 30%]
........................................................................ [ 60%]
............................................................F
=================================== FAILURES ===================================
_______________________ test_issue_comment_help_command ________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f412adc84d0>
mock_github_client = <MagicMock name='github_client' id='139917868560272'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_command(webhook_handler, mock_github_client):
        """Test @stampbot help posts contextual help."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:473: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:45:46.663110Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:45:46.663706Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:45:46.663110Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:45:46.663706Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_command - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 204 passed, 3 deselected, 1 warning in 2.73s
operator: core/AddNot, occurrence: 42, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -593,7 +593,7 @@
 
                 return {
                     "status": "success" if success else "error",
-                    "message": "Help message posted" if success else "Failed to post help message",
+                    "message": "Help message posted" if not success else "Failed to post help message",
                 }
 
             if command in repo_config.approve_commands + repo_config.unapprove_commands:
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.31s
operator: core/AddNot, occurrence: 43, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -596,7 +596,7 @@
                     "message": "Help message posted" if success else "Failed to post help message",
                 }
 
-            if command in repo_config.approve_commands + repo_config.unapprove_commands:
+            if not command in repo_config.approve_commands + repo_config.unapprove_commands:
                 has_permission = await run_in_threadpool(
                     github_client.user_has_permission,
                     installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7faed77f7e50>
mock_github_client = <MagicMock name='github_client' id='140388918534096'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
        assert "approved" in result["message"].lower()
        mock_github_client.approve_pr.assert_called_once()
>       mock_github_client.user_has_permission.assert_called_once()

tests/test_webhook_handler.py:374: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.user_has_permission' id='140388916792352'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'user_has_permission' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:24:46.350169Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:24:46.350789Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:24:46.350169Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:24:46.350789Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: Expected 'user_has_permission' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.79s
operator: core/AddNot, occurrence: 44, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -604,7 +604,7 @@
                     commenter,
                     repo_config.chatops_required_permission,
                 )
-                if not has_permission:
+                if not not has_permission:
                     chatops_commands_total.labels(command=command, status="forbidden").inc()
                     add_span_attributes(
                         span,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f4fda0f57d0>
mock_github_client = <MagicMock name='github_client' id='139980936257488'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:43:06.265065Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:43:06.265666Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:43:06.265065Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:43:06.265666Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.73s
operator: core/AddNot, occurrence: 45, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -622,7 +622,7 @@
                     }
 
             # Handle approve commands
-            if command in repo_config.approve_commands:
+            if not command in repo_config.approve_commands:
                 head_sha = await run_in_threadpool(
                     github_client.get_pr_head_sha,
                     installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f68a87c0250>
mock_github_client = <MagicMock name='github_client' id='140087482081232'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:40:45.527306Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:40:45.527876Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:40:45.527306Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:40:45.527876Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.72s
operator: core/AddNot, occurrence: 46, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -640,7 +640,7 @@
 
                 chatops_commands_total.labels(
                     command="approve",
-                    status="success" if success else "failure",
+                    status="success" if not success else "failure",
                 ).inc()
 
                 add_span_attributes(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/AddNot, occurrence: 47, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -644,7 +644,7 @@
                 ).inc()
 
                 add_span_attributes(
-                    span, {"chatops.result": "approved" if success else "approval_failed"}
+                    span, {"chatops.result": "approved" if not success else "approval_failed"}
                 )
                 set_span_ok(span)
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/AddNot, occurrence: 48, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -649,7 +649,7 @@
                 set_span_ok(span)
 
                 return {
-                    "status": "success" if success else "error",
+                    "status": "success" if not success else "error",
                     "message": "PR approved" if success else "Failed to approve PR",
                 }
 
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f30122417d0>
mock_github_client = <MagicMock name='github_client' id='139844440219600'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:16:39.276413Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:16:39.276987Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:16:39.276413Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:16:39.276987Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.73s
operator: core/AddNot, occurrence: 49, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -650,7 +650,7 @@
 
                 return {
                     "status": "success" if success else "error",
-                    "message": "PR approved" if success else "Failed to approve PR",
+                    "message": "PR approved" if not success else "Failed to approve PR",
                 }
 
             # Handle unapprove commands
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f554e2cdcd0>
mock_github_client = <MagicMock name='github_client' id='140004291370960'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
>       assert "approved" in result["message"].lower()
E       AssertionError: assert 'approved' in 'failed to approve pr'
E        +  where 'failed to approve pr' = <built-in method lower of str object at 0x7f554a0e1370>()
E        +    where <built-in method lower of str object at 0x7f554a0e1370> = 'Failed to approve PR'.lower

tests/test_webhook_handler.py:372: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:54:27.843037Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:54:27.843635Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:54:27.843037Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:54:27.843635Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'approved' in 'failed to approve pr'
 +  where 'failed to approve pr' = <built-in method lower of str object at 0x7f554a0e1370>()
 +    where <built-in method lower of str object at 0x7f554a0e1370> = 'Failed to approve PR'.lower
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.72s
operator: core/AddNot, occurrence: 50, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -665,7 +665,7 @@
 
                 chatops_commands_total.labels(
                     command="unapprove",
-                    status="success" if success else "failure",
+                    status="success" if not success else "failure",
                 ).inc()
 
                 add_span_attributes(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/AddNot, occurrence: 51, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -669,7 +669,7 @@
                 ).inc()
 
                 add_span_attributes(
-                    span, {"chatops.result": "unapproved" if success else "unapprove_failed"}
+                    span, {"chatops.result": "unapproved" if not success else "unapprove_failed"}
                 )
                 set_span_ok(span)
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/AddNot, occurrence: 52, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -674,7 +674,7 @@
                 set_span_ok(span)
 
                 return {
-                    "status": "success" if success else "error",
+                    "status": "success" if not success else "error",
                     "message": "Approvals dismissed" if success else "Failed to dismiss approvals",
                 }
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................F
=================================== FAILURES ===================================
_________________________ test_issue_comment_unapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f8549a0a2d0>
mock_github_client = <MagicMock name='github_client' id='140210442814864'>

    @pytest.mark.asyncio
    async def test_issue_comment_unapprove(webhook_handler, mock_github_client):
        """Test @stampbot unapprove command."""
        payload = load_fixture("issue_comment_unapprove")
        mock_github_client.find_bot_reviews.return_value = [111]
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:420: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:09:34.473681Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:09:34.474251Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:09:34.473681Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:09:34.474251Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_unapprove - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 200 passed, 3 deselected, 1 warning in 2.75s
operator: core/AddNot, occurrence: 53, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -675,7 +675,7 @@
 
                 return {
                     "status": "success" if success else "error",
-                    "message": "Approvals dismissed" if success else "Failed to dismiss approvals",
+                    "message": "Approvals dismissed" if not success else "Failed to dismiss approvals",
                 }
 
             chatops_commands_total.labels(command="unknown", status="ignored").inc()
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................F
=================================== FAILURES ===================================
_________________________ test_issue_comment_unapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f5c7557b830>
mock_github_client = <MagicMock name='github_client' id='140035078473104'>

    @pytest.mark.asyncio
    async def test_issue_comment_unapprove(webhook_handler, mock_github_client):
        """Test @stampbot unapprove command."""
        payload = load_fixture("issue_comment_unapprove")
        mock_github_client.find_bot_reviews.return_value = [111]
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
>       assert "dismissed" in result["message"].lower()
E       AssertionError: assert 'dismissed' in 'failed to dismiss approvals'
E        +  where 'failed to dismiss approvals' = <built-in method lower of str object at 0x7f5c755161f0>()
E        +    where <built-in method lower of str object at 0x7f5c755161f0> = 'Failed to dismiss approvals'.lower

tests/test_webhook_handler.py:421: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:09:14.427976Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:09:14.428551Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:09:14.427976Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:09:14.428551Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_unapprove - AssertionError: assert 'dismissed' in 'failed to dismiss approvals'
 +  where 'failed to dismiss approvals' = <built-in method lower of str object at 0x7f5c755161f0>()
 +    where <built-in method lower of str object at 0x7f5c755161f0> = 'Failed to dismiss approvals'.lower
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 200 passed, 3 deselected, 1 warning in 2.73s
operator: core/AddNot, occurrence: 54, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -719,7 +719,7 @@
                     default_branch,
                 )
 
-                if content:
+                if not content:
                     return self._parse_repo_config(span, content, source_repo=repo_full_name)
 
                 org_repo_full_name = None
........................................................................ [ 30%]
........................................................................ [ 60%]
....................................F
=================================== FAILURES ===================================
_______________ test_pr_label_ignored_when_auto_approve_disabled _______________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fb8663888d0>
mock_github_client = <MagicMock name='github_client' id='140429966439968'>

    @pytest.mark.asyncio
    async def test_pr_label_ignored_when_auto_approve_disabled(webhook_handler, mock_github_client):
        """Test label approvals are ignored when auto_approve_on_label is disabled."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        mock_github_client.get_repo_file.return_value = "auto_approve_on_label = false"
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:115: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:24:30.087322Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:24:30.087880Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:24:30.088576Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:24:30.087322Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:24:30.087880Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:24:30.088576Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_label_ignored_when_auto_approve_disabled - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 180 passed, 3 deselected, 1 warning in 2.64s
operator: core/AddNot, occurrence: 55, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -723,7 +723,7 @@
                     return self._parse_repo_config(span, content, source_repo=repo_full_name)
 
                 org_repo_full_name = None
-                if (
+                if not (
                     owner_type == "Organization"
                     and owner_login
                     and repo_full_name != f"{owner_login}/.github"
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................................F
=================================== FAILURES ===================================
_____________________ test_repo_config_uses_default_branch _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fc5ae761310>
mock_github_client = <MagicMock name='github_client' id='140487010861136'>

    @pytest.mark.asyncio
    async def test_repo_config_uses_default_branch(webhook_handler, mock_github_client):
        """Test repo config is loaded from the default branch."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["repository"]["default_branch"] = "develop"
        payload["pull_request"]["base"]["ref"] = "release"
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        args = mock_github_client.get_repo_file.call_args[0]
>       assert args[3] == "develop"
E       AssertionError: assert None == 'develop'

tests/test_webhook_handler.py:643: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:08:05.374690Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:08:05.375414Z [info     ] No stampbot.toml found in octocat/hello-world or octocat/.github, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': 'octocat/.github'}
2026-06-29T05:08:05.376100Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:08:05.374690Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': 'octocat/.github'}, 'event': 'No stampbot.toml found in octocat/hello-world or octocat/.github, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:08:05.375414Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:08:05.376100Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_repo_config_uses_default_branch - AssertionError: assert None == 'develop'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 213 passed, 3 deselected, 1 warning in 3.17s
operator: core/AddNot, occurrence: 56, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -736,7 +736,7 @@
                         "stampbot.toml",
                         None,
                     )
-                    if org_content:
+                    if not org_content:
                         return self._parse_repo_config(
                             span, org_content, source_repo=org_repo_full_name
                         )
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................................................F
=================================== FAILURES ===================================
_____________________ test_org_github_repo_config_fallback _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f35b7204f50>
mock_github_client = <MagicMock name='github_client' id='139868682925600'>

    @pytest.mark.asyncio
    async def test_org_github_repo_config_fallback(webhook_handler, mock_github_client):
        """Test org .github stampbot.toml is used when repo config is missing."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["repository"]["full_name"] = "acme/widgets"
        payload["repository"]["default_branch"] = "main"
        payload["repository"]["owner"] = {"login": "acme", "type": "Organization"}
        payload["pull_request"]["labels"] = [{"name": "org-approve"}]
    
        def get_repo_file_side_effect(_installation_id, repo_full_name, _file_path, _ref):
            if repo_full_name == "acme/widgets":
                return None
            if repo_full_name == "acme/.github":
                return 'approval_labels = ["org-approve"]'
            return None
    
        mock_github_client.get_repo_file.side_effect = get_repo_file_side_effect
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:666: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:51:29.269964Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:51:29.270830Z [info     ] No stampbot.toml found in acme/widgets or acme/.github, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'acme/widgets', 'org_repo': 'acme/.github'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:51:29.269964Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'acme/widgets', 'org_repo': 'acme/.github'}, 'event': 'No stampbot.toml found in acme/widgets or acme/.github, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:51:29.270830Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_org_github_repo_config_fallback - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 214 passed, 3 deselected, 1 warning in 3.19s
operator: core/AddNot, occurrence: 57, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -745,7 +745,7 @@
                 logger.info(
                     "No stampbot.toml found in %s%s, using defaults",
                     repo_full_name,
-                    f" or {org_repo_full_name}" if org_repo_full_name else "",
+                    f" or {org_repo_full_name}" if not org_repo_full_name else "",
                     extra={"repo": repo_full_name, "org_repo": org_repo_full_name},
                 )
                 add_span_attributes(span, {"config.result": "default"})
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/AddNot, occurrence: 58, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -843,7 +843,7 @@
             ]
         )
 
-        if repo_config.auto_approve_on_label:
+        if not repo_config.auto_approve_on_label:
             approval_labels = ", ".join(f"`{label}`" for label in repo_config.approval_labels)
             lines.append(f"Adding any of these labels can trigger approval: {approval_labels}")
         else:
........................................................................ [ 30%]
........................................................................ [ 60%]
............................................................F
=================================== FAILURES ===================================
_______________________ test_issue_comment_help_command ________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fe42d7a04d0>
mock_github_client = <MagicMock name='github_client' id='140617992105872'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_command(webhook_handler, mock_github_client):
        """Test @stampbot help posts contextual help."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
        assert "help" in result["message"].lower()
        mock_github_client.user_has_permission.assert_not_called()
        mock_github_client.create_issue_comment.assert_called_once()
        comment_args = mock_github_client.create_issue_comment.call_args[0]
        assert comment_args[:3] == (12345, "octocat/hello-world", 42)
        assert "@stampbot approve" in comment_args[3]
        assert "@stampbot unapprove" in comment_args[3]
>       assert "`autoapprove`" in comment_args[3]
E       AssertionError: assert '`autoapprove`' in '## Stampbot Help\n\n### ChatOps Commands\n\nApprove and unapprove commands require **maintain** permission or higher....Help**: `@stampbot help`\n\n### Label-Based Auto-Approval\n\nLabel-based auto-approval is disabled in this repository.'

tests/test_webhook_handler.py:481: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:18:09.382603Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:18:09.383168Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:18:09.382603Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:18:09.383168Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_command - AssertionError: assert '`autoapprove`' in '## Stampbot Help\n\n### ChatOps Commands\n\nApprove and unapprove commands require **maintain** permission or higher....Help**: `@stampbot help`\n\n### Label-Based Auto-Approval\n\nLabel-based auto-approval is disabled in this repository.'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 204 passed, 3 deselected, 1 warning in 2.74s
operator: core/AddNot, occurrence: 59, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -850,7 +850,7 @@
             lines.append("Label-based auto-approval is disabled in this repository.")
 
         filters = []
-        if repo_config.required_labels:
+        if not repo_config.required_labels:
             filters.append(
                 "required labels: "
                 + ", ".join(f"`{label}`" for label in repo_config.required_labels)
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7ff525582630>
mock_github_client = <MagicMock name='github_client' id='140690870420544'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
        help_text = mock_github_client.create_issue_comment.call_args[0][3]
        assert "@stampbot approve-it" in help_text
        assert "@stampbot hold-it" in help_text
        assert "`ship-it`" in help_text
>       assert "`dependencies`" in help_text
E       AssertionError: assert '`dependencies`' in '## Stampbot Help\n\n### ChatOps Commands\n\nApprove and unapprove commands require **maintain** permission or higher....ilters apply:\n- required title patterns: `^chore:`\n- allowed users: `renovate[bot]`\n- allowed teams: `release-team`'

tests/test_webhook_handler.py:506: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:48:32.783320Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:48:32.783320Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - AssertionError: assert '`dependencies`' in '## Stampbot Help\n\n### ChatOps Commands\n\nApprove and unapprove commands require **maintain** permission or higher....ilters apply:\n- required title patterns: `^chore:`\n- allowed users: `renovate[bot]`\n- allowed teams: `release-team`'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.74s
operator: core/AddNot, occurrence: 60, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -855,7 +855,7 @@
                 "required labels: "
                 + ", ".join(f"`{label}`" for label in repo_config.required_labels)
             )
-        if repo_config.required_title_patterns:
+        if not repo_config.required_title_patterns:
             filters.append(
                 "required title patterns: "
                 + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f300df93dd0>
mock_github_client = <MagicMock name='github_client' id='139844369695808'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
        help_text = mock_github_client.create_issue_comment.call_args[0][3]
        assert "@stampbot approve-it" in help_text
        assert "@stampbot hold-it" in help_text
        assert "`ship-it`" in help_text
        assert "`dependencies`" in help_text
>       assert "`^chore:`" in help_text
E       AssertionError: assert '`^chore:`' in '## Stampbot Help\n\n### ChatOps Commands\n\nApprove and unapprove commands require **maintain** permission or higher....l filters apply:\n- required labels: `dependencies`\n- allowed users: `renovate[bot]`\n- allowed teams: `release-team`'

tests/test_webhook_handler.py:507: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:25:42.568764Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:25:42.568764Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - AssertionError: assert '`^chore:`' in '## Stampbot Help\n\n### ChatOps Commands\n\nApprove and unapprove commands require **maintain** permission or higher....l filters apply:\n- required labels: `dependencies`\n- allowed users: `renovate[bot]`\n- allowed teams: `release-team`'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.74s
operator: core/AddNot, occurrence: 61, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -860,7 +860,7 @@
                 "required title patterns: "
                 + ", ".join(f"`{pattern}`" for pattern in repo_config.required_title_patterns)
             )
-        if repo_config.allowed_users:
+        if not repo_config.allowed_users:
             filters.append(
                 "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
             )
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fcb12292030>
mock_github_client = <MagicMock name='github_client' id='140510159946816'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
        help_text = mock_github_client.create_issue_comment.call_args[0][3]
        assert "@stampbot approve-it" in help_text
        assert "@stampbot hold-it" in help_text
        assert "`ship-it`" in help_text
        assert "`dependencies`" in help_text
        assert "`^chore:`" in help_text
>       assert "`renovate[bot]`" in help_text
E       AssertionError: assert '`renovate[bot]`' in '## Stampbot Help\n\n### ChatOps Commands\n\nApprove and unapprove commands require **maintain** permission or higher....lters apply:\n- required labels: `dependencies`\n- required title patterns: `^chore:`\n- allowed teams: `release-team`'

tests/test_webhook_handler.py:508: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:15:17.196668Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:15:17.196668Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - AssertionError: assert '`renovate[bot]`' in '## Stampbot Help\n\n### ChatOps Commands\n\nApprove and unapprove commands require **maintain** permission or higher....lters apply:\n- required labels: `dependencies`\n- required title patterns: `^chore:`\n- allowed teams: `release-team`'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.74s
operator: core/AddNot, occurrence: 62, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -864,7 +864,7 @@
             filters.append(
                 "allowed users: " + ", ".join(f"`{user}`" for user in repo_config.allowed_users)
             )
-        if repo_config.allowed_teams:
+        if not repo_config.allowed_teams:
             filters.append(
                 "allowed teams: " + ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
             )
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f64c4a86630>
mock_github_client = <MagicMock name='github_client' id='140070772999232'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
        help_text = mock_github_client.create_issue_comment.call_args[0][3]
        assert "@stampbot approve-it" in help_text
        assert "@stampbot hold-it" in help_text
        assert "`ship-it`" in help_text
        assert "`dependencies`" in help_text
        assert "`^chore:`" in help_text
        assert "`renovate[bot]`" in help_text
>       assert "`release-team`" in help_text
E       AssertionError: assert '`release-team`' in '## Stampbot Help\n\n### ChatOps Commands\n\nApprove and unapprove commands require **maintain** permission or higher....ters apply:\n- required labels: `dependencies`\n- required title patterns: `^chore:`\n- allowed users: `renovate[bot]`'

tests/test_webhook_handler.py:509: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:34:13.104452Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:34:13.104452Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - AssertionError: assert '`release-team`' in '## Stampbot Help\n\n### ChatOps Commands\n\nApprove and unapprove commands require **maintain** permission or higher....ters apply:\n- required labels: `dependencies`\n- required title patterns: `^chore:`\n- allowed users: `renovate[bot]`'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.74s
operator: core/AddNot, occurrence: 63, definition_name: _format_help_message
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -869,7 +869,7 @@
                 "allowed teams: " + ", ".join(f"`{team}`" for team in repo_config.allowed_teams)
             )
 
-        if filters:
+        if not filters:
             lines.extend(["", "Additional approval filters apply:"])
             lines.extend(f"- {filter_text}" for filter_text in filters)
 
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................................F
=================================== FAILURES ===================================
_______________ test_issue_comment_help_uses_custom_repo_config ________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f069b5825d0>
mock_github_client = <MagicMock name='github_client' id='139666352948288'>

    @pytest.mark.asyncio
    async def test_issue_comment_help_uses_custom_repo_config(webhook_handler, mock_github_client):
        """Test help reflects custom repo commands, labels, and filters."""
        payload = load_fixture("issue_comment_approve")
        payload["comment"]["body"] = "@stampbot help"
        mock_github_client.get_repo_file.return_value = """
    approval_labels = ["ship-it"]
    approve_commands = ["approve-it"]
    unapprove_commands = ["hold-it"]
    required_labels = ["dependencies"]
    required_title_patterns = ["^chore:"]
    allowed_users = ["renovate[bot]"]
    allowed_teams = ["release-team"]
    """
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
        help_text = mock_github_client.create_issue_comment.call_args[0][3]
        assert "@stampbot approve-it" in help_text
        assert "@stampbot hold-it" in help_text
        assert "`ship-it`" in help_text
>       assert "`dependencies`" in help_text
E       AssertionError: assert '`dependencies`' in '## Stampbot Help\n\n### ChatOps Commands\n\nApprove and unapprove commands require **maintain** permission or higher....elp**: `@stampbot help`\n\n### Label-Based Auto-Approval\n\nAdding any of these labels can trigger approval: `ship-it`'

tests/test_webhook_handler.py:506: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:41:45.784579Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:41:45.784579Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_help_uses_custom_repo_config - AssertionError: assert '`dependencies`' in '## Stampbot Help\n\n### ChatOps Commands\n\nApprove and unapprove commands require **maintain** permission or higher....elp**: `@stampbot help`\n\n### Label-Based Auto-Approval\n\nAdding any of these labels can trigger approval: `ship-it`'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 205 passed, 3 deselected, 1 warning in 2.74s
operator: core/AddNot, occurrence: 64, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -935,7 +935,7 @@
                 "approval.trigger_type": trigger_type,
             },
         ) as span:
-            if not skip_existing_check:
+            if not not skip_existing_check:
                 if head_sha:
                     existing_reviews = await run_in_threadpool(
                         github_client.find_bot_approval_reviews,
........................................................................ [ 30%]
........................................................................ [ 60%]
.......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_reapproves_dismissed_review __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f13dc3b1250>
mock_github_client = <MagicMock name='github_client' id='139723276129616'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_reapproves_dismissed_review(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes re-approve when prior Stampbot approval was dismissed."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "DISMISSED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        mock_github_client.approve_pr.assert_called_once()
>       mock_github_client.find_bot_reviews.assert_not_called()

tests/test_webhook_handler.py:164: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_reviews' id='139723277448400'>

    def assert_not_called(self):
        """assert that the mock was never called.
        """
        if self.call_count != 0:
            msg = ("Expected '%s' to not have been called. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'find_bot_reviews' to not have been called. Called 1 times.
E           Calls: [call(12345, 'octocat/hello-world', 42)].

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:947: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:53:04.794879Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T04:53:04.795454Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:53:04.796060Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:53:04.794879Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:53:04.795454Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:53:04.796060Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_reapproves_dismissed_review - AssertionError: Expected 'find_bot_reviews' to not have been called. Called 1 times.
Calls: [call(12345, 'octocat/hello-world', 42)].
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 183 passed, 3 deselected, 1 warning in 2.72s
operator: core/AddNot, occurrence: 65, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -936,7 +936,7 @@
             },
         ) as span:
             if not skip_existing_check:
-                if head_sha:
+                if not head_sha:
                     existing_reviews = await run_in_threadpool(
                         github_client.find_bot_approval_reviews,
                         installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
............................................F
=================================== FAILURES ===================================
___________________ test_pr_labeled_skips_duplicate_approval ___________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f3505b035f0>
mock_github_client = <MagicMock name='github_client' id='139865704100400'>

    @pytest.mark.asyncio
    async def test_pr_labeled_skips_duplicate_approval(webhook_handler, mock_github_client):
        """Test that existing approval prevents duplicate approval comment."""
        payload = load_fixture("pr_labeled_autoapprove")
        # Simulate existing active approval
        mock_github_client.find_bot_reviews.return_value = [12345]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        # find_bot_reviews should be called to check for existing approval
>       mock_github_client.find_bot_reviews.assert_called_once()

tests/test_webhook_handler.py:251: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_reviews' id='139865704098384'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'find_bot_reviews' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:29:34.843874Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T04:29:34.844466Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:29:34.844906Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:29:34.843874Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:29:34.844466Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:29:34.844906Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_skips_duplicate_approval - AssertionError: Expected 'find_bot_reviews' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 188 passed, 3 deselected, 1 warning in 2.75s
operator: core/AddNot, occurrence: 66, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -957,7 +957,7 @@
                         pr_number,
                     )
 
-                if existing_approvals:
+                if not existing_approvals:
                     logger.info(
                         "PR #%d in %s already has active approval for current head, skipping",
                         pr_number,
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f54e3e12ea0>
mock_github_client = <MagicMock name='github_client' id='140002577940896'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        assert "approved" in result["message"].lower()
>       mock_github_client.approve_pr.assert_called_once_with(
            12345,  # installation_id
            "octocat/hello-world",  # repo
            42,  # pr_number
            "Auto-approved by Stampbot (label: autoapprove)",
        )

tests/test_webhook_handler.py:75: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.approve_pr' id='140002577941232'>
args = (12345, 'octocat/hello-world', 42, 'Auto-approved by Stampbot (label: autoapprove)')
kwargs = {}, msg = "Expected 'approve_pr' to be called once. Called 0 times."

    def assert_called_once_with(self, /, *args, **kwargs):
        """assert that the mock was called exactly once and that that call was
        with the specified arguments."""
        if not self.call_count == 1:
            msg = ("Expected '%s' to be called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'approve_pr' to be called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:997: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:02:49.905035Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:02:49.905755Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:02:49.906529Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T05:02:49.906855Z [info     ] PR #42 in octocat/hello-world already has active approval for current head, skipping [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'existing_review_ids': []}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:02:49.905035Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:02:49.905755Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:02:49.906529Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:961 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'existing_review_ids': []}, 'event': 'PR #42 in octocat/hello-world already has active approval for current head, skipping', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:02:49.906855Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: Expected 'approve_pr' to be called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.72s
operator: core/AddNot, occurrence: 67, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -991,7 +991,7 @@
             duration = time.time() - start_time
             pr_approval_duration_seconds.observe(duration)
 
-            status = "success" if success else "failure"
+            status = "success" if not success else "failure"
             pr_approvals_total.labels(
                 trigger_type=trigger_type,
                 status=status,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/AddNot, occurrence: 68, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -997,7 +997,7 @@
                 status=status,
             ).inc()
 
-            if not success:
+            if not not success:
                 errors_total.labels(error_type="approval_failed").inc()
 
             add_span_attributes(span, {"approval.result": status})
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.27s
operator: core/AddNot, occurrence: 69, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1046,7 +1046,7 @@
 
                 add_span_attributes(span, {"dismissal.reviews_found": len(review_ids)})
 
-                if not review_ids:
+                if not not review_ids:
                     logger.info(
                         "No bot approvals found on PR #%d",
                         pr_number,
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f522da49910>
mock_github_client = <MagicMock name='github_client' id='139990928967056'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        assert "dismissed" in result["message"].lower()
        mock_github_client.find_bot_reviews.assert_called_once()
>       assert mock_github_client.dismiss_approval.call_count == 2
E       AssertionError: assert 0 == 2
E        +  where 0 = <MagicMock name='github_client.dismiss_approval' id='139990928968736'>.call_count
E        +    where <MagicMock name='github_client.dismiss_approval' id='139990928968736'> = <MagicMock name='github_client' id='139990928967056'>.dismiss_approval

tests/test_webhook_handler.py:267: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:38:21.682795Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:38:21.683369Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:38:21.683802Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T04:38:21.684214Z [info     ] No bot approvals found on PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:38:21.682795Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:38:21.683369Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:38:21.683802Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:1050 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42}, 'event': 'No bot approvals found on PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:38:21.684214Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 0 == 2
 +  where 0 = <MagicMock name='github_client.dismiss_approval' id='139990928968736'>.call_count
 +    where <MagicMock name='github_client.dismiss_approval' id='139990928968736'> = <MagicMock name='github_client' id='139990928967056'>.dismiss_approval
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.68s
operator: core/AddNot, occurrence: 70, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1075,7 +1075,7 @@
                 duration = time.time() - start_time
                 pr_dismissal_duration_seconds.observe(duration)
 
-                status = "success" if success else "failure"
+                status = "success" if not success else "failure"
                 pr_dismissals_total.labels(trigger_type=trigger_type, status=status).inc()
 
                 add_span_attributes(span, {"dismissal.result": status})
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceTrueWithFalse, occurrence: 0, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -415,7 +415,7 @@
             Tuple of (should approve, skip existing approval check).
         """
         if action in ("opened", "reopened"):
-            return True, False
+            return False, False
 
         added_label = payload.get("label", {}).get("name")
         if action == "labeled" and added_label in repo_config.approval_labels:
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fed8dafeea0>
mock_github_client = <MagicMock name='github_client' id='140658259771808'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:73: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:22:29.867669Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:22:29.868424Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:22:29.867669Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:22:29.868424Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.66s
operator: core/ReplaceTrueWithFalse, occurrence: 1, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -419,7 +419,7 @@
 
         added_label = payload.get("label", {}).get("name")
         if action == "labeled" and added_label in repo_config.approval_labels:
-            return True, False
+            return False, False
 
         if action == "synchronize" and not repo_config.reapprove:
             return False, False
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................F
=================================== FAILURES ===================================
_________________________ test_pr_labeled_autoapprove __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f7955f75260>
mock_github_client = <MagicMock name='github_client' id='140159110797968'>

    @pytest.mark.asyncio
    async def test_pr_labeled_autoapprove(webhook_handler, mock_github_client):
        """Test adding autoapprove label triggers approval."""
        payload = load_fixture("pr_labeled_autoapprove")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:126: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:27:41.603203Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T04:27:41.603803Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:27:41.603203Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:27:41.603803Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_autoapprove - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 181 passed, 3 deselected, 1 warning in 2.65s
operator: core/ReplaceTrueWithFalse, occurrence: 2, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -433,7 +433,7 @@
             repo_full_name,
             pr_number,
         )
-        return self._approval_needs_refresh(reviews, head_sha), True
+        return self._approval_needs_refresh(reviews, head_sha), False
 
     def _approval_needs_refresh(
         self,
........................................................................ [ 30%]
........................................................................ [ 60%]
.......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_reapproves_dismissed_review __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f6dbb5c5750>
mock_github_client = <MagicMock name='github_client' id='140109281236304'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_reapproves_dismissed_review(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes re-approve when prior Stampbot approval was dismissed."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "DISMISSED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        mock_github_client.approve_pr.assert_called_once()
>       mock_github_client.find_bot_reviews.assert_not_called()

tests/test_webhook_handler.py:164: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_reviews' id='140109351680192'>

    def assert_not_called(self):
        """assert that the mock was never called.
        """
        if self.call_count != 0:
            msg = ("Expected '%s' to not have been called. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'find_bot_reviews' to not have been called. Called 1 times.
E           Calls: [call(12345, 'octocat/hello-world', 42)].

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:947: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:59:27.563492Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T04:59:27.564023Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:59:27.564617Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:59:27.563492Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:59:27.564023Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:59:27.564617Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_reapproves_dismissed_review - AssertionError: Expected 'find_bot_reviews' to not have been called. Called 1 times.
Calls: [call(12345, 'octocat/hello-world', 42)].
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 183 passed, 3 deselected, 1 warning in 2.71s
operator: core/ReplaceTrueWithFalse, occurrence: 3, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -475,7 +475,7 @@
 
             review_commit = review.get("commit_id")
             if not head_sha or not review_commit or review_commit == head_sha:
-                return True
+                return False
 
         return False
 
........................................................................ [ 30%]
........................................................................ [ 60%]
..........................................F
=================================== FAILURES ===================================
_________ test_pr_synchronize_reapprove_enabled_current_review_ignored _________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fd94ed842f0>
mock_github_client = <MagicMock name='github_client' id='140571304785104'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_enabled_current_review_ignored(
        webhook_handler, mock_github_client
    ):
        """Test new commits do not re-approve when current head already has approval."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
        mock_github_client.get_repo_file.return_value = "reapprove = true"
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "APPROVED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:217: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:38:57.987480Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
2026-06-29T04:38:57.988518Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:38:57.987480Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:38:57.988518Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_enabled_current_review_ignored - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 186 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceTrueWithFalse, occurrence: 4, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -976,7 +976,7 @@
                         },
                     )
                     set_span_ok(span)
-                    return True
+                    return False
 
             start_time = time.time()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
............................................F
=================================== FAILURES ===================================
___________________ test_pr_labeled_skips_duplicate_approval ___________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f617ab2f5f0>
mock_github_client = <MagicMock name='github_client' id='140056647873072'>

    @pytest.mark.asyncio
    async def test_pr_labeled_skips_duplicate_approval(webhook_handler, mock_github_client):
        """Test that existing approval prevents duplicate approval comment."""
        payload = load_fixture("pr_labeled_autoapprove")
        # Simulate existing active approval
        mock_github_client.find_bot_reviews.return_value = [12345]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:249: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:37:00.739796Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T04:37:00.740365Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:37:00.740804Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T04:37:00.741113Z [info     ] PR #42 in octocat/hello-world already has active approval for current head, skipping [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'existing_review_ids': [12345]}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:37:00.739796Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:37:00.740365Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:37:00.740804Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:961 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'existing_review_ids': [12345]}, 'event': 'PR #42 in octocat/hello-world already has active approval for current head, skipping', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:37:00.741113Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_skips_duplicate_approval - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 188 passed, 3 deselected, 1 warning in 2.69s
operator: core/ReplaceTrueWithFalse, occurrence: 5, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1057,7 +1057,7 @@
                     pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                     add_span_attributes(span, {"dismissal.result": "no_reviews"})
                     set_span_ok(span)
-                    return True
+                    return False
 
                 # Dismiss each review
                 success = True
........................................................................ [ 30%]
........................................................................ [ 60%]
...............................................F
=================================== FAILURES ===================================
_______________________ test_pr_unlabeled_no_bot_reviews _______________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f56d4a5a2b0>
mock_github_client = <MagicMock name='github_client' id='140010911946064'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_no_bot_reviews(webhook_handler, mock_github_client):
        """Test removing label when no bot reviews exist."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = []  # No reviews to dismiss
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:291: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:48:46.975264Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:48:46.975849Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:48:46.976298Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T05:48:46.976720Z [info     ] No bot approvals found on PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:48:46.975264Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:48:46.975849Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:48:46.976298Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:1050 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42}, 'event': 'No bot approvals found on PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:48:46.976720Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_no_bot_reviews - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 191 passed, 3 deselected, 1 warning in 2.69s
operator: core/ReplaceTrueWithFalse, occurrence: 6, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1060,7 +1060,7 @@
                     return True
 
                 # Dismiss each review
-                success = True
+                success = False
                 for review_id in review_ids:
                     result = await run_in_threadpool(
                         github_client.dismiss_approval,
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f3964c55910>
mock_github_client = <MagicMock name='github_client' id='139884479677840'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'error' == 'success'
E         
E         - success
E         + error

tests/test_webhook_handler.py:264: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:59:17.154907Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:59:17.155535Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:59:17.155966Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:59:17.154907Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:59:17.155535Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:59:17.155966Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 'error' == 'success'
  
  - success
  + error
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.68s
operator: core/ReplaceFalseWithTrue, occurrence: 0, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -68,7 +68,7 @@
             True if signature is valid
         """
         if not signature:
-            return False
+            return True
 
         expected_signature = (
             "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
........................................................................ [ 30%]
....................................F
=================================== FAILURES ===================================
________________________ test_webhook_missing_signature ________________________

test_client = <starlette.testclient.TestClient object at 0x7f250f854d10>

    def test_webhook_missing_signature(test_client: TestClient):
        """Test webhook rejects requests without signature."""
        response = test_client.post(
            "/webhook",
            json={"zen": "test"},
            headers={"X-GitHub-Event": "ping"},
        )
>       assert response.status_code == 401
E       assert 200 == 401
E        +  where 200 = <Response [200 OK]>.status_code

tests/test_main.py:131: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:23:52.094081Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T04:23:52.095020Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:23:52.094081Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_missing_signature - assert 200 == 401
 +  where 200 = <Response [200 OK]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 108 passed, 3 deselected, 1 warning in 2.35s
operator: core/ReplaceFalseWithTrue, occurrence: 1, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -77,7 +77,7 @@
         try:
             return hmac.compare_digest(expected_signature, signature)
         except TypeError:
-            return False
+            return True
 
     async def handle_event(
         self,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
......F
=================================== FAILURES ===================================
_______________________ test_verify_signature_non_ascii ________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f1f5ae31d30>

    def test_verify_signature_non_ascii(webhook_handler):
        """Test non-ASCII signature content is rejected."""
        payload = b'{"test": "data"}'
        signature = "sha256=\u2603"
    
>       assert webhook_handler.verify_signature(payload, signature) is False
E       assert True is False
E        +  where True = verify_signature(b'{"test": "data"}', 'sha256=☃')
E        +    where verify_signature = <stampbot.webhook_handler.WebhookHandler object at 0x7f1f5ae31d30>.verify_signature

tests/test_webhook_handler.py:792: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_verify_signature_non_ascii - assert True is False
 +  where True = verify_signature(b'{"test": "data"}', 'sha256=☃')
 +    where verify_signature = <stampbot.webhook_handler.WebhookHandler object at 0x7f1f5ae31d30>.verify_signature
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 222 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceFalseWithTrue, occurrence: 2, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -217,7 +217,7 @@
                         repo_full_name,
                         label,
                     )
-                    if label_exists is False:
+                    if label_exists is True:
                         logger.warning(
                             "Approval label %s not found in %s",
                             label,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceFalseWithTrue, occurrence: 3, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -415,7 +415,7 @@
             Tuple of (should approve, skip existing approval check).
         """
         if action in ("opened", "reopened"):
-            return True, False
+            return True, True
 
         added_label = payload.get("label", {}).get("name")
         if action == "labeled" and added_label in repo_config.approval_labels:
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceFalseWithTrue, occurrence: 4, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -419,7 +419,7 @@
 
         added_label = payload.get("label", {}).get("name")
         if action == "labeled" and added_label in repo_config.approval_labels:
-            return True, False
+            return True, True
 
         if action == "synchronize" and not repo_config.reapprove:
             return False, False
........................................................................ [ 30%]
........................................................................ [ 60%]
............................................F
=================================== FAILURES ===================================
___________________ test_pr_labeled_skips_duplicate_approval ___________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7ff5308fb5f0>
mock_github_client = <MagicMock name='github_client' id='140691059208752'>

    @pytest.mark.asyncio
    async def test_pr_labeled_skips_duplicate_approval(webhook_handler, mock_github_client):
        """Test that existing approval prevents duplicate approval comment."""
        payload = load_fixture("pr_labeled_autoapprove")
        # Simulate existing active approval
        mock_github_client.find_bot_reviews.return_value = [12345]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        # find_bot_reviews should be called to check for existing approval
>       mock_github_client.find_bot_reviews.assert_called_once()

tests/test_webhook_handler.py:251: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_reviews' id='140691059206736'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'find_bot_reviews' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:52:34.573592Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T04:52:34.574161Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:52:34.574618Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:52:34.573592Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:52:34.574161Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:52:34.574618Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_skips_duplicate_approval - AssertionError: Expected 'find_bot_reviews' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 188 passed, 3 deselected, 1 warning in 2.75s
operator: core/ReplaceFalseWithTrue, occurrence: 5, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -422,7 +422,7 @@
             return True, False
 
         if action == "synchronize" and not repo_config.reapprove:
-            return False, False
+            return True, False
 
         if action not in ("labeled", "synchronize"):
             return False, False
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................F
=================================== FAILURES ===================================
____________________ test_pr_synchronize_reapprove_disabled ____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fb290b27b60>
mock_github_client = <MagicMock name='github_client' id='140404904202256'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_disabled(webhook_handler, mock_github_client):
        """Test new commits do not re-approve by default."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:176: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:46:35.544283Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
2026-06-29T04:46:35.545011Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:46:35.545464Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:46:35.544283Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:46:35.545011Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:46:35.545464Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_disabled - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 184 passed, 3 deselected, 1 warning in 2.66s
operator: core/ReplaceFalseWithTrue, occurrence: 6, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -422,7 +422,7 @@
             return True, False
 
         if action == "synchronize" and not repo_config.reapprove:
-            return False, False
+            return False, True
 
         if action not in ("labeled", "synchronize"):
             return False, False
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceFalseWithTrue, occurrence: 7, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -425,7 +425,7 @@
             return False, False
 
         if action not in ("labeled", "synchronize"):
-            return False, False
+            return True, False
 
         reviews = await run_in_threadpool(
             github_client.find_bot_approval_reviews,
........................................................................ [ 30%]
........................................................................ [ 60%]
...........................................F
=================================== FAILURES ===================================
_________________ test_should_approve_for_unsupported_pr_event _________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f2ea937dfd0>

    @pytest.mark.asyncio
    async def test_should_approve_for_unsupported_pr_event(webhook_handler):
        """Test approval decision helper rejects unsupported PR actions."""
        from stampbot.config import RepoConfig
    
        should_approve, skip_existing_check = await webhook_handler._should_approve_for_pr_event(
            "closed",
            {},
            "current-head",
            12345,
            "octocat/hello-world",
            42,
            RepoConfig.default(),
        )
    
>       assert should_approve is False
E       assert True is False

tests/test_webhook_handler.py:236: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_should_approve_for_unsupported_pr_event - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 187 passed, 3 deselected, 1 warning in 2.69s
operator: core/ReplaceFalseWithTrue, occurrence: 8, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -425,7 +425,7 @@
             return False, False
 
         if action not in ("labeled", "synchronize"):
-            return False, False
+            return False, True
 
         reviews = await run_in_threadpool(
             github_client.find_bot_approval_reviews,
........................................................................ [ 30%]
........................................................................ [ 60%]
...........................................F
=================================== FAILURES ===================================
_________________ test_should_approve_for_unsupported_pr_event _________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7efcf1570910>

    @pytest.mark.asyncio
    async def test_should_approve_for_unsupported_pr_event(webhook_handler):
        """Test approval decision helper rejects unsupported PR actions."""
        from stampbot.config import RepoConfig
    
        should_approve, skip_existing_check = await webhook_handler._should_approve_for_pr_event(
            "closed",
            {},
            "current-head",
            12345,
            "octocat/hello-world",
            42,
            RepoConfig.default(),
        )
    
        assert should_approve is False
>       assert skip_existing_check is False
E       assert True is False

tests/test_webhook_handler.py:237: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_should_approve_for_unsupported_pr_event - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 187 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceFalseWithTrue, occurrence: 9, definition_name: _approval_needs_refresh
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -450,7 +450,7 @@
             True when a prior approval exists but no active approval applies to the current head.
         """
         if not reviews:
-            return False
+            return True
 
         return not self._has_current_active_approval(reviews, head_sha)
 
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_with_approval_label_ignored __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f4e317d9950>
mock_github_client = <MagicMock name='github_client' id='139973815975424'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_with_approval_label_ignored(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes do not re-approve just because an approval label exists."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:142: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:27:27.047088Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T04:27:27.047676Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:27:27.048269Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:27:27.047088Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:27:27.047676Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:27:27.048269Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_with_approval_label_ignored - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 182 passed, 3 deselected, 1 warning in 2.65s
operator: core/ReplaceFalseWithTrue, occurrence: 10, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -477,7 +477,7 @@
             if not head_sha or not review_commit or review_commit == head_sha:
                 return True
 
-        return False
+        return True
 
     async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
         """Handle PR comment events for chatops.
........................................................................ [ 30%]
........................................................................ [ 60%]
.......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_reapproves_dismissed_review __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f00fb49d850>
mock_github_client = <MagicMock name='github_client' id='139642192794960'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_reapproves_dismissed_review(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes re-approve when prior Stampbot approval was dismissed."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "DISMISSED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:162: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:50:47.623573Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:50:47.624151Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:50:47.623573Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:50:47.624151Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_reapproves_dismissed_review - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 183 passed, 3 deselected, 1 warning in 2.66s
operator: core/ReplaceFalseWithTrue, occurrence: 11, definition_name: _approve_pr
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -908,7 +908,7 @@
         pr_number: int,
         comment: str,
         trigger_type: str,
-        skip_existing_check: bool = False,
+        skip_existing_check: bool = True,
         head_sha: str | None = None,
     ) -> bool:
         """Approve a PR and track metrics.
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................................F
=================================== FAILURES ===================================
__________________ test_issue_comment_approve_skips_duplicate __________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7ff0266b7af0>
mock_github_client = <MagicMock name='github_client' id='140669341430992'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve_skips_duplicate(webhook_handler, mock_github_client):
        """Test chatops approve skips duplicate when PR already approved."""
        payload = load_fixture("issue_comment_approve")
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 12345, "state": "APPROVED", "commit_id": "current-head"}
        ]
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
        assert result["status"] == "success"
        mock_github_client.get_pr_head_sha.assert_called_once()
>       mock_github_client.find_bot_approval_reviews.assert_called_once()

tests/test_webhook_handler.py:389: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_approval_reviews' id='140669337801056'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:13:25.571461Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:13:25.572011Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:13:25.571461Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:13:25.572011Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve_skips_duplicate - AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 198 passed, 3 deselected, 1 warning in 2.77s
operator: core/ReplaceFalseWithTrue, occurrence: 12, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1100,7 +1100,7 @@
                 errors_total.labels(error_type="dismiss_failed").inc()
 
                 set_span_error(span, e)
-                return False
+                return True
 
 
 # Global handler instance
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
..............F
=================================== FAILURES ===================================
_______________________ test_dismiss_approvals_exception _______________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fcbad06c350>
mock_github_client = <MagicMock name='github_client' id='140512756155792'>

    @pytest.mark.asyncio
    async def test_dismiss_approvals_exception(webhook_handler, mock_github_client):
        """Test _dismiss_approvals handles exceptions gracefully."""
        payload = load_fixture("pr_unlabeled_autoapprove")
    
        # Make find_bot_reviews raise an exception
        mock_github_client.find_bot_reviews.side_effect = Exception("API error")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "error"
E       AssertionError: assert 'success' == 'error'
E         
E         - error
E         + success

tests/test_webhook_handler.py:946: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:14:54.473571Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:14:54.474130Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:14:54.474602Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T04:14:54.474956Z [error    ] Error dismissing approvals: API error [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=error extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'error': 'API error'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:14:54.473571Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:14:54.474130Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:14:54.474602Z'}
ERROR    stampbot.webhook_handler:webhook_handler.py:1091 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'error': 'API error'}, 'event': 'Error dismissing approvals: API error', 'logger': 'stampbot.webhook_handler', 'level': 'error', 'timestamp': '2026-06-29T04:14:54.474956Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_dismiss_approvals_exception - AssertionError: assert 'success' == 'error'
  
  - error
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 230 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceAndWithOr, occurrence: 0, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -226,7 +226,7 @@
                         )
 
             # Check if we should approve based on labels
-            if repo_config.auto_approve_on_label and action in [
+            if repo_config.auto_approve_on_label or action in [
                 "opened",
                 "reopened",
                 "labeled",
........................................................................ [ 30%]
........................................................................ [ 60%]
....................................F
=================================== FAILURES ===================================
_______________ test_pr_label_ignored_when_auto_approve_disabled _______________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f8768d56030>
mock_github_client = <MagicMock name='github_client' id='140219556886048'>

    @pytest.mark.asyncio
    async def test_pr_label_ignored_when_auto_approve_disabled(webhook_handler, mock_github_client):
        """Test label approvals are ignored when auto_approve_on_label is disabled."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        mock_github_client.get_repo_file.return_value = "auto_approve_on_label = false"
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:115: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:47:05.243482Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:47:05.244676Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:47:05.243482Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:47:05.244676Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_label_ignored_when_auto_approve_disabled - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 180 passed, 3 deselected, 1 warning in 2.65s
operator: core/ReplaceAndWithOr, occurrence: 1, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -254,7 +254,7 @@
 
                     # Check if team membership verification is needed
                     author_team_slugs: list[str] | None = None
-                    if repo_config.needs_team_check(pr_author) and owner_login:
+                    if repo_config.needs_team_check(pr_author) or owner_login:
                         author_team_slugs = await run_in_threadpool(
                             github_client.get_user_team_slugs,
                             installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
....................F
=================================== FAILURES ===================================
_________________ test_pr_with_allowed_users_skips_team_check __________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f8009e09df0>
mock_github_client = <MagicMock name='github_client' id='140187898410528'>

    @pytest.mark.asyncio
    async def test_pr_with_allowed_users_skips_team_check(webhook_handler, mock_github_client):
        """Test PR with user in allowed_users skips team membership check."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        # The fixture has user "contributor"
        mock_github_client.get_repo_file.return_value = """
    allowed_users = ["contributor"]
    allowed_teams = ["acme/release-team"]
    """
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        # Should NOT call get_user_team_slugs since user is in allowed_users
>       mock_github_client.get_user_team_slugs.assert_not_called()

tests/test_webhook_handler.py:1065: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.get_user_team_slugs' id='140187898401456'>

    def assert_not_called(self):
        """assert that the mock was never called.
        """
        if self.call_count != 0:
            msg = ("Expected '%s' to not have been called. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'get_user_team_slugs' to not have been called. Called 1 times.
E           Calls: [call(12345, 'octocat', 'contributor', ['acme/release-team'])].

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:947: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:35:09.688556Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:35:09.689799Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:35:09.688556Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:35:09.689799Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_with_allowed_users_skips_team_check - AssertionError: Expected 'get_user_team_slugs' to not have been called. Called 1 times.
Calls: [call(12345, 'octocat', 'contributor', ['acme/release-team'])].
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 236 passed, 3 deselected, 1 warning in 3.27s
operator: core/ReplaceAndWithOr, occurrence: 2, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -332,7 +332,7 @@
                     }
 
             # Check if we should remove approval when label is removed
-            if repo_config.auto_approve_on_label and action == "unlabeled":
+            if repo_config.auto_approve_on_label or action == "unlabeled":
                 removed_label = payload.get("label", {}).get("name")
                 if removed_label in repo_config.approval_labels:
                     logger.info(
........................................................................ [ 30%]
........................................................................ [ 60%]
..............................................F
=================================== FAILURES ===================================
_____________ test_pr_unlabeled_ignored_when_auto_approve_disabled _____________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fcd66085910>
mock_github_client = <MagicMock name='github_client' id='140520155261856'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_ignored_when_auto_approve_disabled(webhook_handler, mock_github_client):
        """Test label removal is ignored when auto_approve_on_label is disabled."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.get_repo_file.return_value = "auto_approve_on_label = false"
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:278: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:40:17.795198Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:40:17.796146Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
2026-06-29T05:40:17.796630Z [info     ] No bot approvals found on PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:40:17.795198Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:40:17.796146Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:1050 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42}, 'event': 'No bot approvals found on PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:40:17.796630Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_ignored_when_auto_approve_disabled - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 190 passed, 3 deselected, 1 warning in 2.69s
operator: core/ReplaceAndWithOr, occurrence: 3, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -418,7 +418,7 @@
             return True, False
 
         added_label = payload.get("label", {}).get("name")
-        if action == "labeled" and added_label in repo_config.approval_labels:
+        if action == "labeled" or added_label in repo_config.approval_labels:
             return True, False
 
         if action == "synchronize" and not repo_config.reapprove:
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_with_approval_label_ignored __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f4b6bed9250>
mock_github_client = <MagicMock name='github_client' id='139961979665920'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_with_approval_label_ignored(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes do not re-approve just because an approval label exists."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:142: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:27:02.383458Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T05:27:02.384019Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:27:02.384492Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:27:02.383458Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:27:02.384019Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:27:02.384492Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_with_approval_label_ignored - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 182 passed, 3 deselected, 1 warning in 2.68s
operator: core/ReplaceAndWithOr, occurrence: 4, definition_name: _should_approve_for_pr_event
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -421,7 +421,7 @@
         if action == "labeled" and added_label in repo_config.approval_labels:
             return True, False
 
-        if action == "synchronize" and not repo_config.reapprove:
+        if action == "synchronize" or not repo_config.reapprove:
             return False, False
 
         if action not in ("labeled", "synchronize"):
........................................................................ [ 30%]
........................................................................ [ 60%]
......................................F
=================================== FAILURES ===================================
_________ test_pr_labeled_unrelated_label_with_approval_label_ignored __________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fda952c5250>
mock_github_client = <MagicMock name='github_client' id='140576794279424'>

    @pytest.mark.asyncio
    async def test_pr_labeled_unrelated_label_with_approval_label_ignored(
        webhook_handler, mock_github_client
    ):
        """Test unrelated label changes do not re-approve just because an approval label exists."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["label"] = {"name": "bug"}
        payload["pull_request"]["labels"].append({"name": "bug"})
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "ignored"
        assert "no action" in result["message"].lower()
>       mock_github_client.find_bot_approval_reviews.assert_called_once()

tests/test_webhook_handler.py:144: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_approval_reviews' id='140576791989952'>

    def assert_called_once(self):
        """assert that the mock was called only once.
        """
        if not self.call_count == 1:
            msg = ("Expected '%s' to have been called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:965: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:33:30.273052Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'labeled'}
2026-06-29T04:33:30.273626Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'labeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:33:30.273052Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:33:30.273626Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_labeled_unrelated_label_with_approval_label_ignored - AssertionError: Expected 'find_bot_approval_reviews' to have been called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 182 passed, 3 deselected, 1 warning in 2.69s
operator: core/ReplaceAndWithOr, occurrence: 5, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -725,7 +725,7 @@
                 org_repo_full_name = None
                 if (
                     owner_type == "Organization"
-                    and owner_login
+                    or owner_login
                     and repo_full_name != f"{owner_login}/.github"
                 ):
                     org_repo_full_name = f"{owner_login}/.github"
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................................F
=================================== FAILURES ===================================
_____________________ test_repo_config_uses_default_branch _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fc25580cdd0>
mock_github_client = <MagicMock name='github_client' id='140472633491536'>

    @pytest.mark.asyncio
    async def test_repo_config_uses_default_branch(webhook_handler, mock_github_client):
        """Test repo config is loaded from the default branch."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["repository"]["default_branch"] = "develop"
        payload["pull_request"]["base"]["ref"] = "release"
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        args = mock_github_client.get_repo_file.call_args[0]
>       assert args[3] == "develop"
E       AssertionError: assert None == 'develop'

tests/test_webhook_handler.py:643: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:19:30.396004Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:19:30.396713Z [info     ] No stampbot.toml found in octocat/hello-world or octocat/.github, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': 'octocat/.github'}
2026-06-29T05:19:30.397409Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:19:30.396004Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': 'octocat/.github'}, 'event': 'No stampbot.toml found in octocat/hello-world or octocat/.github, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:19:30.396713Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:19:30.397409Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_repo_config_uses_default_branch - AssertionError: assert None == 'develop'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 213 passed, 3 deselected, 1 warning in 3.18s
operator: core/ReplaceAndWithOr, occurrence: 6, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -726,7 +726,7 @@
                 if (
                     owner_type == "Organization"
                     and owner_login
-                    and repo_full_name != f"{owner_login}/.github"
+                    or repo_full_name != f"{owner_login}/.github"
                 ):
                     org_repo_full_name = f"{owner_login}/.github"
                     org_content = await run_in_threadpool(
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................................F
=================================== FAILURES ===================================
_____________________ test_repo_config_uses_default_branch _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7feca4e328d0>
mock_github_client = <MagicMock name='github_client' id='140654350123088'>

    @pytest.mark.asyncio
    async def test_repo_config_uses_default_branch(webhook_handler, mock_github_client):
        """Test repo config is loaded from the default branch."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["repository"]["default_branch"] = "develop"
        payload["pull_request"]["base"]["ref"] = "release"
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        args = mock_github_client.get_repo_file.call_args[0]
>       assert args[3] == "develop"
E       AssertionError: assert None == 'develop'

tests/test_webhook_handler.py:643: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:14:57.684214Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:14:57.684932Z [info     ] No stampbot.toml found in octocat/hello-world or octocat/.github, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': 'octocat/.github'}
2026-06-29T05:14:57.685629Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:14:57.684214Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': 'octocat/.github'}, 'event': 'No stampbot.toml found in octocat/hello-world or octocat/.github, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:14:57.684932Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:14:57.685629Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_repo_config_uses_default_branch - AssertionError: assert None == 'develop'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 213 passed, 3 deselected, 1 warning in 3.19s
operator: core/ReplaceAndWithOr, occurrence: 7, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1070,7 +1070,7 @@
                         review_id,
                         message,
                     )
-                    success = success and result
+                    success = success or result
 
                 duration = time.time() - start_time
                 pr_dismissal_duration_seconds.observe(duration)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.30s
operator: core/ReplaceOrWithAnd, occurrence: 0, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -146,7 +146,7 @@
         pr_number = pr.get("number")
         repo = payload.get("repository", {})
         repo_full_name = repo.get("full_name")
-        repo_default_branch = repo.get("default_branch") or "main"
+        repo_default_branch = repo.get("default_branch") and "main"
         repo_owner = repo.get("owner", {})
         owner_login = repo_owner.get("login")
         owner_type = repo_owner.get("type")
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................................F
=================================== FAILURES ===================================
_____________________ test_repo_config_uses_default_branch _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fcdd33ac4d0>
mock_github_client = <MagicMock name='github_client' id='140521987145808'>

    @pytest.mark.asyncio
    async def test_repo_config_uses_default_branch(webhook_handler, mock_github_client):
        """Test repo config is loaded from the default branch."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        payload["repository"]["default_branch"] = "develop"
        payload["pull_request"]["base"]["ref"] = "release"
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        args = mock_github_client.get_repo_file.call_args[0]
>       assert args[3] == "develop"
E       AssertionError: assert 'main' == 'develop'
E         
E         - develop
E         + main

tests/test_webhook_handler.py:643: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:17:13.864654Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:17:13.865242Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:17:13.865924Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:17:13.864654Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:17:13.865242Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:17:13.865924Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_repo_config_uses_default_branch - AssertionError: assert 'main' == 'develop'
  
  - develop
  + main
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 213 passed, 3 deselected, 1 warning in 3.17s
operator: core/ReplaceOrWithAnd, occurrence: 1, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -155,7 +155,7 @@
         with create_span(
             "webhook.handle_pull_request",
             {
-                "github.repo": repo_full_name or "unknown",
+                "github.repo": repo_full_name and "unknown",
                 "github.pr_number": pr_number or 0,
                 "github.action": action or "unknown",
             },
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceOrWithAnd, occurrence: 2, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -156,7 +156,7 @@
             "webhook.handle_pull_request",
             {
                 "github.repo": repo_full_name or "unknown",
-                "github.pr_number": pr_number or 0,
+                "github.pr_number": pr_number and 0,
                 "github.action": action or "unknown",
             },
         ) as span:
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceOrWithAnd, occurrence: 3, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -157,7 +157,7 @@
             {
                 "github.repo": repo_full_name or "unknown",
                 "github.pr_number": pr_number or 0,
-                "github.action": action or "unknown",
+                "github.action": action and "unknown",
             },
         ) as span:
             if not all([pr_number, repo_full_name, installation_id]):
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceOrWithAnd, occurrence: 4, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -474,7 +474,7 @@
                 continue
 
             review_commit = review.get("commit_id")
-            if not head_sha or not review_commit or review_commit == head_sha:
+            if not head_sha and not review_commit or review_commit == head_sha:
                 return True
 
         return False
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceOrWithAnd, occurrence: 5, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -474,7 +474,7 @@
                 continue
 
             review_commit = review.get("commit_id")
-            if not head_sha or not review_commit or review_commit == head_sha:
+            if not head_sha or not review_commit and review_commit == head_sha:
                 return True
 
         return False
........................................................................ [ 30%]
........................................................................ [ 60%]
..........................................F
=================================== FAILURES ===================================
_________ test_pr_synchronize_reapprove_enabled_current_review_ignored _________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fd233f83150>
mock_github_client = <MagicMock name='github_client' id='140540789191888'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_enabled_current_review_ignored(
        webhook_handler, mock_github_client
    ):
        """Test new commits do not re-approve when current head already has approval."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
        mock_github_client.get_repo_file.return_value = "reapprove = true"
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "APPROVED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:217: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:35:53.709148Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
2026-06-29T04:35:53.710188Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:35:53.709148Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:35:53.710188Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_enabled_current_review_ignored - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 186 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceOrWithAnd, occurrence: 6, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -513,7 +513,7 @@
 
         repo = payload.get("repository", {})
         repo_full_name = repo.get("full_name")
-        repo_default_branch = repo.get("default_branch") or "main"
+        repo_default_branch = repo.get("default_branch") and "main"
         repo_owner = repo.get("owner", {})
         owner_login = repo_owner.get("login")
         owner_type = repo_owner.get("type")
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceOrWithAnd, occurrence: 7, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -523,7 +523,7 @@
         with create_span(
             "webhook.handle_chatops",
             {
-                "github.repo": repo_full_name or "unknown",
+                "github.repo": repo_full_name and "unknown",
                 "github.pr_number": pr_number,
                 "chatops.commenter": commenter,
             },
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceOrWithAnd, occurrence: 8, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -708,7 +708,7 @@
         """
         with create_span(
             "webhook.get_repo_config",
-            {"github.repo": repo_full_name, "github.ref": default_branch or "default"},
+            {"github.repo": repo_full_name, "github.ref": default_branch and "default"},
         ) as span:
             try:
                 content = await run_in_threadpool(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceContinueWithBreak, occurrence: 0, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -471,7 +471,7 @@
         """
         for review in reviews:
             if review["state"] != "APPROVED":
-                continue
+                break
 
             review_commit = review.get("commit_id")
             if not head_sha or not review_commit or review_commit == head_sha:
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ExceptionReplacer, occurrence: 0, definition_name: verify_signature
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -76,7 +76,7 @@
 
         try:
             return hmac.compare_digest(expected_signature, signature)
-        except TypeError:
+        except CosmicRayTestingException:
             return False
 
     async def handle_event(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
......F
=================================== FAILURES ===================================
_______________________ test_verify_signature_non_ascii ________________________

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f7982d25d30>
payload = b'{"test": "data"}', signature = 'sha256=☃'

    def verify_signature(self, payload: bytes, signature: str) -> bool:
        """Verify GitHub webhook signature.
    
        Args:
            payload: Request payload
            signature: X-Hub-Signature-256 header value
    
        Returns:
            True if signature is valid
        """
        if not signature:
            return False
    
        expected_signature = (
            "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
        )
    
        try:
>           return hmac.compare_digest(expected_signature, signature)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: comparing strings with non-ASCII characters is not supported

stampbot/webhook_handler.py:78: TypeError

During handling of the above exception, another exception occurred:

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f7982d25d30>

    def test_verify_signature_non_ascii(webhook_handler):
        """Test non-ASCII signature content is rejected."""
        payload = b'{"test": "data"}'
        signature = "sha256=\u2603"
    
>       assert webhook_handler.verify_signature(payload, signature) is False
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:792: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f7982d25d30>
payload = b'{"test": "data"}', signature = 'sha256=☃'

    def verify_signature(self, payload: bytes, signature: str) -> bool:
        """Verify GitHub webhook signature.
    
        Args:
            payload: Request payload
            signature: X-Hub-Signature-256 header value
    
        Returns:
            True if signature is valid
        """
        if not signature:
            return False
    
        expected_signature = (
            "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
        )
    
        try:
            return hmac.compare_digest(expected_signature, signature)
>       except CosmicRayTestingException:
               ^^^^^^^^^^^^^^^^^^^^^^^^^
E       NameError: name 'CosmicRayTestingException' is not defined

stampbot/webhook_handler.py:79: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_verify_signature_non_ascii - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 222 passed, 3 deselected, 1 warning in 3.26s
operator: core/ExceptionReplacer, occurrence: 1, definition_name: _get_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -752,7 +752,7 @@
                 set_span_ok(span)
                 return RepoConfig.default()
 
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 repo_config_loads_total.labels(status="error").inc()
                 logger.warning(
                     "Error loading config from %s: %s, using defaults",
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.............F
=================================== FAILURES ===================================
________________________ test_get_repo_config_exception ________________________

self = <stampbot.webhook_handler.WebhookHandler object at 0x7ff001e10f50>
installation_id = 12345, repo_full_name = 'octocat/hello-world'
default_branch = 'main', owner_login = 'octocat', owner_type = 'User'

    async def _get_repo_config(
        self,
        installation_id: int,
        repo_full_name: str,
        default_branch: str,
        owner_login: str | None,
        owner_type: str | None,
    ) -> RepoConfig:
        """Get repository configuration from stampbot.toml.
    
        Reads from the repo's default branch first, then falls back to the
        organization-wide .github repo if available.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            default_branch: Repository default branch
            owner_login: Repository owner login
            owner_type: Repository owner type (Organization/User)
    
        Returns:
            RepoConfig instance (default if file not found)
        """
        with create_span(
            "webhook.get_repo_config",
            {"github.repo": repo_full_name, "github.ref": default_branch or "default"},
        ) as span:
            try:
>               content = await run_in_threadpool(
                    github_client.get_repo_file,
                    installation_id,
                    repo_full_name,
                    "stampbot.toml",
                    default_branch,
                )

stampbot/webhook_handler.py:714: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/concurrency.py:34: in run_in_threadpool
    return await anyio.to_thread.run_sync(func)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/to_thread.py:63: in run_sync
    return await get_async_backend().run_sync_in_worker_thread(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:2596: in run_sync_in_worker_thread
    return await future
           ^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:1029: in run
    result = context.run(func, *args)
             ^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.get_repo_file' id='140668802620048'>
args = (12345, 'octocat/hello-world', 'stampbot.toml', 'main'), kwargs = {}
effect = Exception('Network error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Network error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7ff001e10f50>
mock_github_client = <MagicMock name='github_client' id='140668802619712'>

    @pytest.mark.asyncio
    async def test_get_repo_config_exception(webhook_handler, mock_github_client):
        """Test _get_repo_config handles exceptions gracefully."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        # Make get_repo_file raise an exception
        mock_github_client.get_repo_file.side_effect = Exception("Network error")
    
        # Should still work, using defaults
>       result = await webhook_handler.handle_event("pull_request", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:930: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:116: in handle_event
    result = await self._handle_pull_request(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:170: in _handle_pull_request
    repo_config = await self._get_repo_config(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7ff001e10f50>
installation_id = 12345, repo_full_name = 'octocat/hello-world'
default_branch = 'main', owner_login = 'octocat', owner_type = 'User'

    async def _get_repo_config(
        self,
        installation_id: int,
        repo_full_name: str,
        default_branch: str,
        owner_login: str | None,
        owner_type: str | None,
    ) -> RepoConfig:
        """Get repository configuration from stampbot.toml.
    
        Reads from the repo's default branch first, then falls back to the
        organization-wide .github repo if available.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            default_branch: Repository default branch
            owner_login: Repository owner login
            owner_type: Repository owner type (Organization/User)
    
        Returns:
            RepoConfig instance (default if file not found)
        """
        with create_span(
            "webhook.get_repo_config",
            {"github.repo": repo_full_name, "github.ref": default_branch or "default"},
        ) as span:
            try:
                content = await run_in_threadpool(
                    github_client.get_repo_file,
                    installation_id,
                    repo_full_name,
                    "stampbot.toml",
                    default_branch,
                )
    
                if content:
                    return self._parse_repo_config(span, content, source_repo=repo_full_name)
    
                org_repo_full_name = None
                if (
                    owner_type == "Organization"
                    and owner_login
                    and repo_full_name != f"{owner_login}/.github"
                ):
                    org_repo_full_name = f"{owner_login}/.github"
                    org_content = await run_in_threadpool(
                        github_client.get_repo_file,
                        installation_id,
                        org_repo_full_name,
                        "stampbot.toml",
                        None,
                    )
                    if org_content:
                        return self._parse_repo_config(
                            span, org_content, source_repo=org_repo_full_name
                        )
    
                repo_config_loads_total.labels(status="default").inc()
                logger.info(
                    "No stampbot.toml found in %s%s, using defaults",
                    repo_full_name,
                    f" or {org_repo_full_name}" if org_repo_full_name else "",
                    extra={"repo": repo_full_name, "org_repo": org_repo_full_name},
                )
                add_span_attributes(span, {"config.result": "default"})
                set_span_ok(span)
                return RepoConfig.default()
    
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/webhook_handler.py:755: NameError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:37:30.939938Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:37:30.939938Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_get_repo_config_exception - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 229 passed, 3 deselected, 1 warning in 3.45s
operator: core/ExceptionReplacer, occurrence: 2, definition_name: _parse_repo_config
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -782,7 +782,7 @@
         """
         try:
             repo_config = RepoConfig.from_toml(toml_content)
-        except ValueError as e:
+        except CosmicRayTestingException as e:
             repo_config_loads_total.labels(status="error").inc()
             add_span_attributes(
                 span,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.F
=================================== FAILURES ===================================
____________________ test_invalid_repo_config_posts_review _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7ff7703a44d0>
mock_github_client = <MagicMock name='github_client' id='140700716375680'>

    @pytest.mark.asyncio
    async def test_invalid_repo_config_posts_review(webhook_handler, mock_github_client):
        """Test invalid repo config logs and posts a review comment."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        mock_github_client.get_repo_file.return_value = 'chatops_required_permission = "invalid"'
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "error"
E       AssertionError: assert 'success' == 'error'
E         
E         - error
E         + success

tests/test_webhook_handler.py:725: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:00:17.267953Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:00:17.268868Z [warning  ] Error loading config from octocat/hello-world: name 'CosmicRayTestingException' is not defined, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=warning extra={'repo': 'octocat/hello-world', 'error': "name 'CosmicRayTestingException' is not defined"}
2026-06-29T05:00:17.269565Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:00:17.267953Z'}
WARNING  stampbot.webhook_handler:webhook_handler.py:757 {'extra': {'repo': 'octocat/hello-world', 'error': "name 'CosmicRayTestingException' is not defined"}, 'event': "Error loading config from octocat/hello-world: name 'CosmicRayTestingException' is not defined, using defaults", 'logger': 'stampbot.webhook_handler', 'level': 'warning', 'timestamp': '2026-06-29T05:00:17.268868Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:00:17.269565Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_invalid_repo_config_posts_review - AssertionError: assert 'success' == 'error'
  
  - error
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 217 passed, 3 deselected, 1 warning in 3.19s
operator: core/ExceptionReplacer, occurrence: 3, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1083,7 +1083,7 @@
 
                 return success
 
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 duration = time.time() - start_time
                 pr_dismissal_duration_seconds.observe(duration)
                 pr_dismissals_total.labels(trigger_type=trigger_type, status="failure").inc()
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
..............F
=================================== FAILURES ===================================
_______________________ test_dismiss_approvals_exception _______________________

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f8504f47a70>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
message = 'Label autoapprove removed', trigger_type = 'label_removed'

    async def _dismiss_approvals(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
        trigger_type: str,
    ) -> bool:
        """Dismiss bot approvals on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            message: Dismissal message
            trigger_type: What triggered the dismissal (label_removed, chatops)
    
        Returns:
            True if successful
        """
        with create_span(
            "webhook.dismiss_approvals",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "dismissal.trigger_type": trigger_type,
            },
        ) as span:
            start_time = time.time()
    
            try:
                # Find all bot reviews
>               review_ids = await run_in_threadpool(
                    github_client.find_bot_reviews,
                    installation_id,
                    repo_full_name,
                    pr_number,
                )

stampbot/webhook_handler.py:1040: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/concurrency.py:34: in run_in_threadpool
    return await anyio.to_thread.run_sync(func)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/to_thread.py:63: in run_sync
    return await get_async_backend().run_sync_in_worker_thread(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:2596: in run_sync_in_worker_thread
    return await future
           ^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/_backends/_asyncio.py:1029: in run
    result = context.run(func, *args)
             ^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='github_client.find_bot_reviews' id='140209289186672'>
args = (12345, 'octocat/hello-world', 42), kwargs = {}
effect = Exception('API error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f8504f47a70>
mock_github_client = <MagicMock name='github_client' id='140209289184656'>

    @pytest.mark.asyncio
    async def test_dismiss_approvals_exception(webhook_handler, mock_github_client):
        """Test _dismiss_approvals handles exceptions gracefully."""
        payload = load_fixture("pr_unlabeled_autoapprove")
    
        # Make find_bot_reviews raise an exception
        mock_github_client.find_bot_reviews.side_effect = Exception("API error")
    
>       result = await webhook_handler.handle_event("pull_request", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:944: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:116: in handle_event
    result = await self._handle_pull_request(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:350: in _handle_pull_request
    success = await self._dismiss_approvals(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f8504f47a70>
installation_id = 12345, repo_full_name = 'octocat/hello-world', pr_number = 42
message = 'Label autoapprove removed', trigger_type = 'label_removed'

    async def _dismiss_approvals(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
        trigger_type: str,
    ) -> bool:
        """Dismiss bot approvals on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name
            pr_number: PR number
            message: Dismissal message
            trigger_type: What triggered the dismissal (label_removed, chatops)
    
        Returns:
            True if successful
        """
        with create_span(
            "webhook.dismiss_approvals",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "dismissal.trigger_type": trigger_type,
            },
        ) as span:
            start_time = time.time()
    
            try:
                # Find all bot reviews
                review_ids = await run_in_threadpool(
                    github_client.find_bot_reviews,
                    installation_id,
                    repo_full_name,
                    pr_number,
                )
    
                add_span_attributes(span, {"dismissal.reviews_found": len(review_ids)})
    
                if not review_ids:
                    logger.info(
                        "No bot approvals found on PR #%d",
                        pr_number,
                        extra={"repo": repo_full_name, "pr_number": pr_number},
                    )
                    duration = time.time() - start_time
                    pr_dismissal_duration_seconds.observe(duration)
                    pr_dismissals_total.labels(trigger_type=trigger_type, status="success").inc()
                    add_span_attributes(span, {"dismissal.result": "no_reviews"})
                    set_span_ok(span)
                    return True
    
                # Dismiss each review
                success = True
                for review_id in review_ids:
                    result = await run_in_threadpool(
                        github_client.dismiss_approval,
                        installation_id,
                        repo_full_name,
                        pr_number,
                        review_id,
                        message,
                    )
                    success = success and result
    
                duration = time.time() - start_time
                pr_dismissal_duration_seconds.observe(duration)
    
                status = "success" if success else "failure"
                pr_dismissals_total.labels(trigger_type=trigger_type, status=status).inc()
    
                add_span_attributes(span, {"dismissal.result": status})
                set_span_ok(span)
    
                return success
    
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/webhook_handler.py:1086: NameError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:43:01.009317Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T04:43:01.009889Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T04:43:01.010361Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:43:01.009317Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:43:01.009889Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:43:01.010361Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_dismiss_approvals_exception - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 230 passed, 3 deselected, 1 warning in 3.46s
operator: core/NumberReplacer, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -29,7 +29,7 @@
 logger = get_logger(__name__)
 
 # Security: Maximum length for user-controlled strings to prevent DoS
-MAX_COMMENT_LENGTH = 65536  # 64KB - generous but prevents abuse
+MAX_COMMENT_LENGTH = 65537  # 64KB - generous but prevents abuse
 
 
 class WebhookHandler:
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/NumberReplacer, occurrence: 1, definition_name: None
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -29,7 +29,7 @@
 logger = get_logger(__name__)
 
 # Security: Maximum length for user-controlled strings to prevent DoS
-MAX_COMMENT_LENGTH = 65536  # 64KB - generous but prevents abuse
+MAX_COMMENT_LENGTH = 65535  # 64KB - generous but prevents abuse
 
 
 class WebhookHandler:
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/NumberReplacer, occurrence: 2, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -156,7 +156,7 @@
             "webhook.handle_pull_request",
             {
                 "github.repo": repo_full_name or "unknown",
-                "github.pr_number": pr_number or 0,
+                "github.pr_number": pr_number or 1,
                 "github.action": action or "unknown",
             },
         ) as span:
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/NumberReplacer, occurrence: 3, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -156,7 +156,7 @@
             "webhook.handle_pull_request",
             {
                 "github.repo": repo_full_name or "unknown",
-                "github.pr_number": pr_number or 0,
+                "github.pr_number": pr_number or -1,
                 "github.action": action or "unknown",
             },
         ) as span:
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/NumberReplacer, occurrence: 4, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -505,7 +505,7 @@
         if "pull_request" in payload.get("issue", {}):
             pr_url = payload["issue"]["pull_request"]["url"]
             # Extract PR number from URL
-            pr_number = int(pr_url.split("/")[-1])
+            pr_number = int(pr_url.split("/")[- 2])
         elif "pull_request" in payload:
             pr_number = payload["pull_request"]["number"]
         else:
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f79e60ebf50>
mock_github_client = <MagicMock name='github_client' id='140161529536464'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f79e60ebf50>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
>           pr_number = int(pr_url.split("/")[- 2])
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           ValueError: invalid literal for int() with base 10: 'pulls'

stampbot/webhook_handler.py:508: ValueError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:41:08.319290Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:41:08.319290Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - ValueError: invalid literal for int() with base 10: 'pulls'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.77s
operator: core/NumberReplacer, occurrence: 5, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -505,7 +505,7 @@
         if "pull_request" in payload.get("issue", {}):
             pr_url = payload["issue"]["pull_request"]["url"]
             # Extract PR number from URL
-            pr_number = int(pr_url.split("/")[-1])
+            pr_number = int(pr_url.split("/")[- 0])
         elif "pull_request" in payload:
             pr_number = payload["pull_request"]["number"]
         else:
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f54930de9d0>
mock_github_client = <MagicMock name='github_client' id='140001222156240'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7f54930de9d0>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
>           pr_number = int(pr_url.split("/")[- 0])
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           ValueError: invalid literal for int() with base 10: 'https:'

stampbot/webhook_handler.py:508: ValueError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:39:42.449344Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:39:42.449344Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - ValueError: invalid literal for int() with base 10: 'https:'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.77s
operator: core/NumberReplacer, occurrence: 6, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -570,7 +570,7 @@
                 set_span_ok(span)
                 return {"status": "ignored", "message": "No command found"}
 
-            command = command_match.group(1).lower()
+            command = command_match.group( 2).lower()
             add_span_attributes(span, {"chatops.command": command})
 
             if command == "help":
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fc947fbbb50>
mock_github_client = <MagicMock name='github_client' id='140502543015888'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
>       result = await webhook_handler.handle_event("issue_comment", payload)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_webhook_handler.py:369: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/webhook_handler.py:122: in handle_event
    result = await self._handle_pr_comment(payload)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.webhook_handler.WebhookHandler object at 0x7fc947fbbb50>
payload = {'action': 'created', 'comment': {'body': '@stampbot approve\n\nLGTM, approving this PR.', 'created_at': '2025-01-10T1...U='}, 'issue': {'assignee': None, 'assignees': [], 'body': 'This PR adds a new feature.', 'closed_at': None, ...}, ...}

    async def _handle_pr_comment(self, payload: dict[str, Any]) -> dict[str, Any]:
        """Handle PR comment events for chatops.
    
        Args:
            payload: Event payload
    
        Returns:
            Response dictionary
        """
        comment = payload.get("comment", {})
        comment_body = comment.get("body", "")
    
        # Security: limit comment length to prevent DoS
        if len(comment_body) > MAX_COMMENT_LENGTH:
            return {"status": "ignored", "message": "Comment too long"}
    
        comment_body = comment_body.lower().strip()
    
        # Check if bot is mentioned
        if "@stampbot" not in comment_body:
            return {"status": "ignored", "message": "Bot not mentioned"}
    
        # Extract PR info
        if "pull_request" in payload.get("issue", {}):
            pr_url = payload["issue"]["pull_request"]["url"]
            # Extract PR number from URL
            pr_number = int(pr_url.split("/")[-1])
        elif "pull_request" in payload:
            pr_number = payload["pull_request"]["number"]
        else:
            return {"status": "error", "message": "Not a PR comment"}
    
        repo = payload.get("repository", {})
        repo_full_name = repo.get("full_name")
        repo_default_branch = repo.get("default_branch") or "main"
        repo_owner = repo.get("owner", {})
        owner_login = repo_owner.get("login")
        owner_type = repo_owner.get("type")
        installation_id = payload.get("installation", {}).get("id")
        commenter = comment.get("user", {}).get("login", "unknown")
    
        with create_span(
            "webhook.handle_chatops",
            {
                "github.repo": repo_full_name or "unknown",
                "github.pr_number": pr_number,
                "chatops.commenter": commenter,
            },
        ) as span:
            if not all([pr_number, repo_full_name, installation_id]):
                logger.warning("Missing required fields in comment event")
                add_span_attributes(span, {"chatops.result": "missing_fields"})
                set_span_ok(span)
                return {"status": "error", "message": "Missing required fields"}
    
            # Get repository configuration
            repo_config = await self._get_repo_config(
                installation_id,
                repo_full_name,
                repo_default_branch,
                owner_login,
                owner_type,
            )
    
            if repo_config.config_error:
                add_span_attributes(
                    span,
                    {
                        "chatops.result": "config_error",
                        "chatops.config_error": repo_config.config_error,
                    },
                )
                set_span_ok(span)
                return {
                    "status": "error",
                    "message": "Invalid repository configuration",
                }
    
            if not repo_config.chatops_enabled:
                add_span_attributes(span, {"chatops.result": "disabled"})
                set_span_ok(span)
                return {"status": "ignored", "message": "Chatops not enabled"}
    
            # Parse command
            command_match = re.search(r"@stampbot\s+(\w+)", comment_body)
            if not command_match:
                chatops_commands_total.labels(command="none", status="ignored").inc()
                add_span_attributes(span, {"chatops.result": "no_command"})
                set_span_ok(span)
                return {"status": "ignored", "message": "No command found"}
    
>           command = command_match.group( 2).lower()
                      ^^^^^^^^^^^^^^^^^^^^^^^
E           IndexError: no such group

stampbot/webhook_handler.py:573: IndexError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:25:07.193763Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T04:25:07.194366Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:25:07.193763Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:25:07.194366Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - IndexError: no such group
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.78s
operator: core/NumberReplacer, occurrence: 7, definition_name: _handle_pr_comment
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -570,7 +570,7 @@
                 set_span_ok(span)
                 return {"status": "ignored", "message": "No command found"}
 
-            command = command_match.group(1).lower()
+            command = command_match.group( 0).lower()
             add_span_attributes(span, {"chatops.command": command})
 
             if command == "help":
........................................................................ [ 30%]
........................................................................ [ 60%]
.....................................................F
=================================== FAILURES ===================================
__________________________ test_issue_comment_approve __________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f66c7223dd0>
mock_github_client = <MagicMock name='github_client' id='140079330467792'>

    @pytest.mark.asyncio
    async def test_issue_comment_approve(webhook_handler, mock_github_client):
        """Test @stampbot approve command."""
        payload = load_fixture("issue_comment_approve")
    
        result = await webhook_handler.handle_event("issue_comment", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:371: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:43:54.857170Z [info     ] Received issue_comment event   [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'issue_comment', 'action': 'created'}
2026-06-29T05:43:54.857759Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'issue_comment', 'action': 'created'}, 'event': 'Received issue_comment event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:43:54.857170Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:43:54.857759Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_issue_comment_approve - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 197 passed, 3 deselected, 1 warning in 2.71s
operator: core/RemoveDecorator, occurrence: 0, definition_name: WebhookHandler
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -38,8 +38,6 @@
     def __init__(self) -> None:
         """Initialize webhook handler (lazy initialization)."""
         self._webhook_secret: bytes | None = None
-
-    @property
     def webhook_secret(self) -> bytes:
         """Get webhook secret, initializing if needed.
 
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7fbcd2d86250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
>       response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )

tests/test_main.py:111: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:337: in webhook
    if not webhook_handler.verify_signature(body, x_hub_signature_256):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/webhook_handler.py:72: in verify_signature
    "sha256=" + hmac.new(self.webhook_secret, payload, hashlib.sha256).hexdigest()
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/hmac.py:218: in new
    return HMAC(key, msg, digestmod)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <hmac.HMAC object at 0x7fbcd2de0220>
key = <bound method WebhookHandler.webhook_secret of <stampbot.webhook_handler.WebhookHandler object at 0x7fbcd2fe6270>>
msg = b'{"test": "data"}', digestmod = <built-in function openssl_sha256>

    def __init__(self, key, msg=None, digestmod=''):
        """Create a new HMAC object.
    
        key: bytes or buffer, key for the keyed hash object.
        msg: bytes or buffer, Initial input for the hash or None.
        digestmod: A hash name suitable for hashlib.new(). *OR*
                   A hashlib constructor returning a new hash object. *OR*
                   A module supporting PEP 247.
    
                   Required as of 3.8, despite its position after the optional
                   msg argument.  Passing it as a keyword argument is
                   recommended, though not required for legacy API reasons.
        """
    
        if not isinstance(key, (bytes, bytearray)):
>           raise TypeError(f"key: expected bytes or bytearray, "
                            f"but got {type(key).__name__!r}")
E           TypeError: key: expected bytes or bytearray, but got 'method'

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/hmac.py:71: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - TypeError: key: expected bytes or bytearray, but got 'method'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.71s
operator: core/ZeroIterationForLoop, occurrence: 0, definition_name: _handle_pull_request
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -210,7 +210,7 @@
                 }
 
             if action == "opened":
-                for label in repo_config.approval_labels:
+                for label in []:
                     label_exists = await run_in_threadpool(
                         github_client.repo_has_label,
                         installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
...................................F
=================================== FAILURES ===================================
__________________ test_pr_opened_missing_label_logs_warning ___________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f8ef9ecee70>
mock_github_client = <MagicMock name='github_client' id='140252056464960'>

    @pytest.mark.asyncio
    async def test_pr_opened_missing_label_logs_warning(webhook_handler, mock_github_client):
        """Test missing approval label triggers label check."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
        mock_github_client.repo_has_label.return_value = False
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
>       assert mock_github_client.repo_has_label.call_count == 2
E       AssertionError: assert 0 == 2
E        +  where 0 = <MagicMock name='github_client.repo_has_label' id='140252056468320'>.call_count
E        +    where <MagicMock name='github_client.repo_has_label' id='140252056468320'> = <MagicMock name='github_client' id='140252056464960'>.repo_has_label

tests/test_webhook_handler.py:104: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:14:04.189330Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T05:14:04.189906Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:14:04.190382Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:14:04.189330Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:14:04.189906Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:14:04.190382Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_missing_label_logs_warning - AssertionError: assert 0 == 2
 +  where 0 = <MagicMock name='github_client.repo_has_label' id='140252056468320'>.call_count
 +    where <MagicMock name='github_client.repo_has_label' id='140252056468320'> = <MagicMock name='github_client' id='140252056464960'>.repo_has_label
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 179 passed, 3 deselected, 1 warning in 2.70s
operator: core/ZeroIterationForLoop, occurrence: 1, definition_name: _find_approval_label
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -385,7 +385,7 @@
         Returns:
             Matching approval label, if present.
         """
-        for label in labels:
+        for label in []:
             if label in repo_config.approval_labels:
                 return label
         return None
........................................................................ [ 30%]
........................................................................ [ 60%]
.................................F
=================================== FAILURES ===================================
____________________ test_pr_opened_with_autoapprove_label _____________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f72d9a42ea0>
mock_github_client = <MagicMock name='github_client' id='140131253092768'>

    @pytest.mark.asyncio
    async def test_pr_opened_with_autoapprove_label(webhook_handler, mock_github_client):
        """Test PR opened with autoapprove label triggers approval."""
        payload = load_fixture("pr_opened_with_autoapprove_label")
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "success"
E       AssertionError: assert 'ignored' == 'success'
E         
E         - success
E         + ignored

tests/test_webhook_handler.py:73: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:38:16.737876Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'opened'}
2026-06-29T04:38:16.738617Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'opened'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:38:16.737876Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:38:16.738617Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_opened_with_autoapprove_label - AssertionError: assert 'ignored' == 'success'
  
  - success
  + ignored
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 177 passed, 3 deselected, 1 warning in 2.63s
operator: core/ZeroIterationForLoop, occurrence: 2, definition_name: _has_current_active_approval
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -469,7 +469,7 @@
             True when an active approval exists for the current head, or when
             GitHub did not provide enough commit information to prove staleness.
         """
-        for review in reviews:
+        for review in []:
             if review["state"] != "APPROVED":
                 continue
 
........................................................................ [ 30%]
........................................................................ [ 60%]
..........................................F
=================================== FAILURES ===================================
_________ test_pr_synchronize_reapprove_enabled_current_review_ignored _________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7fc6c88882f0>
mock_github_client = <MagicMock name='github_client' id='140491742098640'>

    @pytest.mark.asyncio
    async def test_pr_synchronize_reapprove_enabled_current_review_ignored(
        webhook_handler, mock_github_client
    ):
        """Test new commits do not re-approve when current head already has approval."""
        payload = load_fixture("pr_labeled_autoapprove")
        payload["action"] = "synchronize"
        payload.pop("label", None)
        mock_github_client.get_repo_file.return_value = "reapprove = true"
        mock_github_client.find_bot_approval_reviews.return_value = [
            {"id": 123, "state": "APPROVED", "commit_id": "abc123def456"}
        ]
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
>       assert result["status"] == "ignored"
E       AssertionError: assert 'success' == 'ignored'
E         
E         - ignored
E         + success

tests/test_webhook_handler.py:217: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:35:18.510113Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'synchronize'}
2026-06-29T04:35:18.511159Z [info     ] PR #42 has approval label: autoapprove [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'synchronize'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:35:18.510113Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:295 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'PR #42 has approval label: autoapprove', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:35:18.511159Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_synchronize_reapprove_enabled_current_review_ignored - AssertionError: assert 'success' == 'ignored'
  
  - ignored
  + success
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 186 passed, 3 deselected, 1 warning in 2.68s
operator: core/ZeroIterationForLoop, occurrence: 3, definition_name: _dismiss_approvals
--- mutation diff ---
--- astampbot/webhook_handler.py
+++ bstampbot/webhook_handler.py
@@ -1061,7 +1061,7 @@
 
                 # Dismiss each review
                 success = True
-                for review_id in review_ids:
+                for review_id in []:
                     result = await run_in_threadpool(
                         github_client.dismiss_approval,
                         installation_id,
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................................F
=================================== FAILURES ===================================
________________________ test_pr_unlabeled_autoapprove _________________________

webhook_handler = <stampbot.webhook_handler.WebhookHandler object at 0x7f686f475910>
mock_github_client = <MagicMock name='github_client' id='140086530966928'>

    @pytest.mark.asyncio
    async def test_pr_unlabeled_autoapprove(webhook_handler, mock_github_client):
        """Test removing autoapprove label dismisses approvals."""
        payload = load_fixture("pr_unlabeled_autoapprove")
        mock_github_client.find_bot_reviews.return_value = [111, 222]  # Mock review IDs
    
        result = await webhook_handler.handle_event("pull_request", payload)
    
        assert result["status"] == "success"
        assert "dismissed" in result["message"].lower()
        mock_github_client.find_bot_reviews.assert_called_once()
>       assert mock_github_client.dismiss_approval.call_count == 2
E       AssertionError: assert 0 == 2
E        +  where 0 = <MagicMock name='github_client.dismiss_approval' id='140086530968608'>.call_count
E        +    where <MagicMock name='github_client.dismiss_approval' id='140086530968608'> = <MagicMock name='github_client' id='140086530966928'>.dismiss_approval

tests/test_webhook_handler.py:267: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:02:04.594463Z [info     ] Received pull_request event    [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'event_type': 'pull_request', 'action': 'unlabeled'}
2026-06-29T05:02:04.595034Z [info     ] No stampbot.toml found in octocat/hello-world, using defaults [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'org_repo': None}
2026-06-29T05:02:04.595479Z [info     ] Approval label autoapprove removed from PR #42 [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info extra={'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'pull_request', 'action': 'unlabeled'}, 'event': 'Received pull_request event', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:02:04.594463Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:745 {'extra': {'repo': 'octocat/hello-world', 'org_repo': None}, 'event': 'No stampbot.toml found in octocat/hello-world, using defaults', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:02:04.595034Z'}
INFO     stampbot.webhook_handler:webhook_handler.py:338 {'extra': {'repo': 'octocat/hello-world', 'pr_number': 42, 'label': 'autoapprove'}, 'event': 'Approval label autoapprove removed from PR #42', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:02:04.595479Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_webhook_handler.py::test_pr_unlabeled_autoapprove - AssertionError: assert 0 == 2
 +  where 0 = <MagicMock name='github_client.dismiss_approval' id='140086530968608'>.call_count
 +    where <MagicMock name='github_client.dismiss_approval' id='140086530968608'> = <MagicMock name='github_client' id='140086530966928'>.dismiss_approval
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 189 passed, 3 deselected, 1 warning in 2.74s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/__main__.py
+++ bstampbot/__main__.py
@@ -7,7 +7,7 @@
 
 from stampbot.config import settings
 
-if __name__ == "__main__":
+if __name__ != "__main__":
     uvicorn.run(
         "stampbot.main:app",
         host=settings.host,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.21s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/__main__.py
+++ bstampbot/__main__.py
@@ -7,7 +7,7 @@
 
 from stampbot.config import settings
 
-if __name__ == "__main__":
+if __name__ < "__main__":
     uvicorn.run(
         "stampbot.main:app",
         host=settings.host,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/__main__.py
+++ bstampbot/__main__.py
@@ -7,7 +7,7 @@
 
 from stampbot.config import settings
 
-if __name__ == "__main__":
+if __name__ <= "__main__":
     uvicorn.run(
         "stampbot.main:app",
         host=settings.host,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.29s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/__main__.py
+++ bstampbot/__main__.py
@@ -7,7 +7,7 @@
 
 from stampbot.config import settings
 
-if __name__ == "__main__":
+if __name__ > "__main__":
     uvicorn.run(
         "stampbot.main:app",
         host=settings.host,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/__main__.py
+++ bstampbot/__main__.py
@@ -7,7 +7,7 @@
 
 from stampbot.config import settings
 
-if __name__ == "__main__":
+if __name__ >= "__main__":
     uvicorn.run(
         "stampbot.main:app",
         host=settings.host,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/__main__.py
+++ bstampbot/__main__.py
@@ -7,7 +7,7 @@
 
 from stampbot.config import settings
 
-if __name__ == "__main__":
+if __name__ is "__main__":
     uvicorn.run(
         "stampbot.main:app",
         host=settings.host,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/__main__.py
+++ bstampbot/__main__.py
@@ -7,7 +7,7 @@
 
 from stampbot.config import settings
 
-if __name__ == "__main__":
+if __name__ is not "__main__":
     uvicorn.run(
         "stampbot.main:app",
         host=settings.host,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/AddNot, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/__main__.py
+++ bstampbot/__main__.py
@@ -7,7 +7,7 @@
 
 from stampbot.config import settings
 
-if __name__ == "__main__":
+if not __name__ == "__main__":
     uvicorn.run(
         "stampbot.main:app",
         host=settings.host,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceFalseWithTrue, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/__main__.py
+++ bstampbot/__main__.py
@@ -13,6 +13,6 @@
         host=settings.host,
         port=settings.port,
         log_level=settings.log_level.lower(),
-        reload=False,
+        reload=True,
     )
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/NumberReplacer, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=( 1.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:30: in <module>
    http_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 1, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=( -0.995, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [-0.995, 0.01....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
E             
E             At index 0 diff: -0.995 != 0.005
E             
E             Full diff:
E               [
E             -     0.005,
E             ?       ^^
E             +     -0.995,
E             ?     +  ^^
E                   0.01,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [-0.995, 0.01....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
  
  At index 0 diff: -0.995 != 0.005
  
  Full diff:
    [
  -     0.005,
  ?       ^^
  +     -0.995,
  ?     +  ^^
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 2, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 1.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:30: in <module>
    http_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.79s
operator: core/NumberReplacer, occurrence: 3, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, -0.99, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:30: in <module>
    http_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 4, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 1.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:30: in <module>
    http_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 5, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, -0.975, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:30: in <module>
    http_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.79s
operator: core/NumberReplacer, occurrence: 6, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, 1.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:30: in <module>
    http_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 7, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, -0.95, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:30: in <module>
    http_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 8, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, 0.05, 1.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:30: in <module>
    http_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 9, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, 0.05, -0.9, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:30: in <module>
    http_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 10, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 1.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:30: in <module>
    http_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 11, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, -0.75, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:30: in <module>
    http_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 12, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 1.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:30: in <module>
    http_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 13, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, -0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:30: in <module>
    http_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 14, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 2.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.005, 0.01,....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
E             
E             At index 7 diff: 2.0 != 1.0
E             
E             Full diff:
E               [
E                   0.005,
E                   0.01,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E             -     1.0,
E             ?     ^
E             +     2.0,
E             ?     ^
E                   2.5,
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.005, 0.01,....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
  
  At index 7 diff: 2.0 != 1.0
  
  Full diff:
    [
        0.005,
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
  -     1.0,
  ?     ^
  +     2.0,
  ?     ^
        2.5,
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 15, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 0.0, 2.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:30: in <module>
    http_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 16, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 3.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.005, 0.01,....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
E             
E             At index 8 diff: 3.5 != 2.5
E             
E             Full diff:
E               [
E                   0.005,
E                   0.01,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E             -     2.5,
E             ?     ^
E             +     3.5,
E             ?     ^
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.005, 0.01,....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
  
  At index 8 diff: 3.5 != 2.5
  
  Full diff:
    [
        0.005,
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
  -     2.5,
  ?     ^
  +     3.5,
  ?     ^
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.57s
operator: core/NumberReplacer, occurrence: 17, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 1.5, 5.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.005, 0.01,....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
E             
E             At index 8 diff: 1.5 != 2.5
E             
E             Full diff:
E               [
E                   0.005,
E                   0.01,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E             -     2.5,
E             ?     ^
E             +     1.5,
E             ?     ^
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.005, 0.01,....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
  
  At index 8 diff: 1.5 != 2.5
  
  Full diff:
    [
        0.005,
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
  -     2.5,
  ?     ^
  +     1.5,
  ?     ^
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 18, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 6.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.005, 0.01,....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
E             
E             At index 9 diff: 6.0 != 5.0
E             
E             Full diff:
E               [
E                   0.005,
E                   0.01,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E             -     5.0,
E             ?     ^
E             +     6.0,
E             ?     ^
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.005, 0.01,....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
  
  At index 9 diff: 6.0 != 5.0
  
  Full diff:
    [
        0.005,
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
  -     5.0,
  ?     ^
  +     6.0,
  ?     ^
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 19, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 4.0, 10.0),
 )
 
 http_request_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.005, 0.01,....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
E             
E             At index 9 diff: 4.0 != 5.0
E             
E             Full diff:
E               [
E                   0.005,
E                   0.01,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E             -     5.0,
E             ?     ^
E             +     4.0,
E             ?     ^
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.005, 0.01,....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
  
  At index 9 diff: 4.0 != 5.0
  
  Full diff:
    [
        0.005,
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
  -     5.0,
  ?     ^
  +     4.0,
  ?     ^
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 20, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 11.0),
 )
 
 http_request_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.005, 0.01,....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
E             
E             At index 10 diff: 11.0 != 10.0
E             
E             Full diff:
E               [
E                   0.005,
E                   0.01,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E             -     10.0,
E             ?      ^
E             +     11.0,
E             ?      ^
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.005, 0.01,....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
  
  At index 10 diff: 11.0 != 10.0
  
  Full diff:
    [
        0.005,
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
  -     10.0,
  ?      ^
  +     11.0,
  ?      ^
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 21, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -31,7 +31,7 @@
     "stampbot_http_request_duration_seconds",
     "HTTP request duration in seconds",
     ["method", "endpoint"],
-    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 9.0),
 )
 
 http_request_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.005, 0.01,....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
E             
E             At index 10 diff: 9.0 != 10.0
E             
E             Full diff:
E               [
E                   0.005,
E                   0.01,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E             -     10.0,
E             ?     ^^
E             +     9.0,
E             ?     ^
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.005, 0.01,....1, 0.25, ...] == [0.005, 0.01,....1, 0.25, ...]
  
  At index 10 diff: 9.0 != 10.0
  
  Full diff:
    [
        0.005,
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
  -     10.0,
  ?     ^^
  +     9.0,
  ?     ^
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 22, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=( 101, 500, 1000, 5000, 10000, 50000, 100000, 500000),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [101.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 0 diff: 101.0 != 100
E             
E             Full diff:
E               [
E             -     100,
E             +     101.0,
E             ?       ++
E             -     500,
E             -     1000,
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [101.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 0 diff: 101.0 != 100
  
  Full diff:
    [
  -     100,
  +     101.0,
  ?       ++
  -     500,
  -     1000,
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 23, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=( 99, 500, 1000, 5000, 10000, 50000, 100000, 500000),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [99.0, 500.0,... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 0 diff: 99.0 != 100
E             
E             Full diff:
E               [
E             +     99.0,
E             -     100,
E             -     500,
E             -     1000,
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [99.0, 500.0,... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 0 diff: 99.0 != 100
  
  Full diff:
    [
  +     99.0,
  -     100,
  -     500,
  -     1000,
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.58s
operator: core/NumberReplacer, occurrence: 24, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 501, 1000, 5000, 10000, 50000, 100000, 500000),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 501.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 1 diff: 501.0 != 500
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             ?       ^
E             +     501.0,
E             ?       ^^
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 501.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 1 diff: 501.0 != 500
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  ?       ^
  +     501.0,
  ?       ^^
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 25, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 499, 1000, 5000, 10000, 50000, 100000, 500000),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 499.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 1 diff: 499.0 != 500
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     499.0,
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 499.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 1 diff: 499.0 != 500
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     499.0,
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 26, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1001, 5000, 10000, 50000, 100000, 500000),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 2 diff: 1001.0 != 1000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             ?        ^
E             +     1001.0,
E             ?        ^^
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 2 diff: 1001.0 != 1000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  ?        ^
  +     1001.0,
  ?        ^^
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.57s
operator: core/NumberReplacer, occurrence: 27, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 999, 5000, 10000, 50000, 100000, 500000),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 2 diff: 999.0 != 1000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     999.0,
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 2 diff: 999.0 != 1000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     999.0,
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 28, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5001, 10000, 50000, 100000, 500000),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 3 diff: 5001.0 != 5000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             ?        ^
E             +     5001.0,
E             ?        ^^
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 3 diff: 5001.0 != 5000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  ?        ^
  +     5001.0,
  ?        ^^
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 29, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 4999, 10000, 50000, 100000, 500000),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 3 diff: 4999.0 != 5000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     4999.0,
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 3 diff: 4999.0 != 5000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     4999.0,
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.57s
operator: core/NumberReplacer, occurrence: 30, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 10001, 50000, 100000, 500000),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 4 diff: 10001.0 != 10000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             ?         ^
E             +     10001.0,
E             ?         ^^
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 4 diff: 10001.0 != 10000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  ?         ^
  +     10001.0,
  ?         ^^
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 31, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 9999, 50000, 100000, 500000),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 4 diff: 9999.0 != 10000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     9999.0,
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 4 diff: 9999.0 != 10000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     9999.0,
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.54s
operator: core/NumberReplacer, occurrence: 32, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 10000, 50001, 100000, 500000),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50001.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 5 diff: 50001.0 != 50000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             ?         ^
E             +     50001.0,
E             ?         ^^
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50001.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 5 diff: 50001.0 != 50000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  ?         ^
  +     50001.0,
  ?         ^^
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 33, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 10000, 49999, 100000, 500000),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 49999.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 5 diff: 49999.0 != 50000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             +     49999.0,
E             -     500000,
E             ?     ^
E             +     100000.0,
E             ?     ^     ++
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 49999.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 5 diff: 49999.0 != 50000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  +     49999.0,
  -     500000,
  ?     ^
  +     100000.0,
  ?     ^     ++
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.57s
operator: core/NumberReplacer, occurrence: 34, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 10000, 50000, 100001, 500000),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 6 diff: 100001.0 != 100000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100001.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 6 diff: 100001.0 != 100000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100001.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 35, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 10000, 50000, 99999, 500000),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 6 diff: 99999.0 != 100000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     99999.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 6 diff: 99999.0 != 100000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     99999.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 36, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500001),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 7 diff: 500001.0 != 500000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500001.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 7 diff: 500001.0 != 500000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500001.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.54s
operator: core/NumberReplacer, occurrence: 37, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -38,7 +38,7 @@
     "stampbot_http_request_size_bytes",
     "HTTP request body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 499999),
 )
 
 http_response_size_bytes = Histogram(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 7 diff: 499999.0 != 500000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     499999.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 7 diff: 499999.0 != 500000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     499999.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 38, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=( 101, 500, 1000, 5000, 10000, 50000, 100000, 500000),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [101.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 0 diff: 101.0 != 100
E             
E             Full diff:
E               [
E             -     100,
E             +     101.0,
E             ?       ++
E             -     500,
E             -     1000,
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [101.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 0 diff: 101.0 != 100
  
  Full diff:
    [
  -     100,
  +     101.0,
  ?       ++
  -     500,
  -     1000,
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.54s
operator: core/NumberReplacer, occurrence: 39, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=( 99, 500, 1000, 5000, 10000, 50000, 100000, 500000),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [99.0, 500.0,... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 0 diff: 99.0 != 100
E             
E             Full diff:
E               [
E             +     99.0,
E             -     100,
E             -     500,
E             -     1000,
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [99.0, 500.0,... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 0 diff: 99.0 != 100
  
  Full diff:
    [
  +     99.0,
  -     100,
  -     500,
  -     1000,
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 40, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 501, 1000, 5000, 10000, 50000, 100000, 500000),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 501.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 1 diff: 501.0 != 500
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             ?       ^
E             +     501.0,
E             ?       ^^
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 501.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 1 diff: 501.0 != 500
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  ?       ^
  +     501.0,
  ?       ^^
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 41, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 499, 1000, 5000, 10000, 50000, 100000, 500000),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 499.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 1 diff: 499.0 != 500
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     499.0,
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 499.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 1 diff: 499.0 != 500
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     499.0,
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 42, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1001, 5000, 10000, 50000, 100000, 500000),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 2 diff: 1001.0 != 1000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             ?        ^
E             +     1001.0,
E             ?        ^^
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 2 diff: 1001.0 != 1000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  ?        ^
  +     1001.0,
  ?        ^^
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 43, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 999, 5000, 10000, 50000, 100000, 500000),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 2 diff: 999.0 != 1000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     999.0,
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 2 diff: 999.0 != 1000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     999.0,
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.54s
operator: core/NumberReplacer, occurrence: 44, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5001, 10000, 50000, 100000, 500000),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 3 diff: 5001.0 != 5000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             ?        ^
E             +     5001.0,
E             ?        ^^
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 3 diff: 5001.0 != 5000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  ?        ^
  +     5001.0,
  ?        ^^
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 45, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 4999, 10000, 50000, 100000, 500000),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 3 diff: 4999.0 != 5000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     4999.0,
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 3 diff: 4999.0 != 5000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     4999.0,
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.57s
operator: core/NumberReplacer, occurrence: 46, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 10001, 50000, 100000, 500000),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 4 diff: 10001.0 != 10000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             ?         ^
E             +     10001.0,
E             ?         ^^
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 4 diff: 10001.0 != 10000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  ?         ^
  +     10001.0,
  ?         ^^
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 47, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 9999, 50000, 100000, 500000),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 4 diff: 9999.0 != 10000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     9999.0,
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 4 diff: 9999.0 != 10000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     9999.0,
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 48, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 10000, 50001, 100000, 500000),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50001.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 5 diff: 50001.0 != 50000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             ?         ^
E             +     50001.0,
E             ?         ^^
E             +     100000.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50001.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 5 diff: 50001.0 != 50000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  ?         ^
  +     50001.0,
  ?         ^^
  +     100000.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.58s
operator: core/NumberReplacer, occurrence: 49, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 10000, 49999, 100000, 500000),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 49999.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 5 diff: 49999.0 != 50000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             +     49999.0,
E             -     500000,
E             ?     ^
E             +     100000.0,
E             ?     ^     ++
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 49999.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 5 diff: 49999.0 != 50000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  +     49999.0,
  -     500000,
  ?     ^
  +     100000.0,
  ?     ^     ++
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 50, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 10000, 50000, 100001, 500000),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 6 diff: 100001.0 != 100000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100001.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 6 diff: 100001.0 != 100000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100001.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.54s
operator: core/NumberReplacer, occurrence: 51, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 10000, 50000, 99999, 500000),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 6 diff: 99999.0 != 100000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     99999.0,
E             +     500000.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 6 diff: 99999.0 != 100000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     99999.0,
  +     500000.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 52, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500001),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 7 diff: 500001.0 != 500000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     500001.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 7 diff: 500001.0 != 500000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     500001.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.57s
operator: core/NumberReplacer, occurrence: 53, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -45,7 +45,7 @@
     "stampbot_http_response_size_bytes",
     "HTTP response body size in bytes",
     ["method", "endpoint"],
-    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
+    buckets=(100, 500, 1000, 5000, 10000, 50000, 100000, 499999),
 )
 
 http_requests_in_progress = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
E             
E             At index 7 diff: 499999.0 != 500000
E             
E             Full diff:
E               [
E             -     100,
E             -     500,
E             -     1000,
E             +     100.0,
E             ?        +
E             -     5000,
E             +     500.0,
E             ?        +
E             -     10000,
E             +     1000.0,
E             ?         +
E             -     50000,
E             +     5000.0,
E             ?         +
E             -     100000,
E             +     10000.0,
E             ?          +
E             -     500000,
E             +     50000.0,
E             ?          +
E             +     100000.0,
E             +     499999.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [100.0, 500.0... 50000.0, ...] == [100, 500, 10...0, 50000, ...]
  
  At index 7 diff: 499999.0 != 500000
  
  Full diff:
    [
  -     100,
  -     500,
  -     1000,
  +     100.0,
  ?        +
  -     5000,
  +     500.0,
  ?        +
  -     10000,
  +     1000.0,
  ?         +
  -     50000,
  +     5000.0,
  ?         +
  -     100000,
  +     10000.0,
  ?          +
  -     500000,
  +     50000.0,
  ?          +
  +     100000.0,
  +     499999.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.54s
operator: core/NumberReplacer, occurrence: 54, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=( 1.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:73: in <module>
    webhook_processing_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.81s
operator: core/NumberReplacer, occurrence: 55, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=( -0.99, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [-0.99, 0.025....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
E             
E             At index 0 diff: -0.99 != 0.01
E             
E             Full diff:
E               [
E             -     0.01,
E             +     -0.99,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [-0.99, 0.025....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
  
  At index 0 diff: -0.99 != 0.01
  
  Full diff:
    [
  -     0.01,
  +     -0.99,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.54s
operator: core/NumberReplacer, occurrence: 56, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 1.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:73: in <module>
    webhook_processing_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 57, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, -0.975, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:73: in <module>
    webhook_processing_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 58, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, 1.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:73: in <module>
    webhook_processing_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 59, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, -0.95, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:73: in <module>
    webhook_processing_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 60, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, 0.05, 1.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:73: in <module>
    webhook_processing_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.81s
operator: core/NumberReplacer, occurrence: 61, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, 0.05, -0.9, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:73: in <module>
    webhook_processing_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 62, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, 0.05, 0.1, 1.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:73: in <module>
    webhook_processing_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 63, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, 0.05, 0.1, -0.75, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:73: in <module>
    webhook_processing_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 64, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 1.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:73: in <module>
    webhook_processing_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.79s
operator: core/NumberReplacer, occurrence: 65, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, -0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:73: in <module>
    webhook_processing_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.81s
operator: core/NumberReplacer, occurrence: 66, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 2.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.01, 0.025,....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
E             
E             At index 6 diff: 2.0 != 1.0
E             
E             Full diff:
E               [
E                   0.01,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E             -     1.0,
E             ?     ^
E             +     2.0,
E             ?     ^
E                   2.5,
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.01, 0.025,....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
  
  At index 6 diff: 2.0 != 1.0
  
  Full diff:
    [
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
  -     1.0,
  ?     ^
  +     2.0,
  ?     ^
        2.5,
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 67, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 0.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:73: in <module>
    webhook_processing_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.81s
operator: core/NumberReplacer, occurrence: 68, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 3.5, 5.0, 10.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.01, 0.025,....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
E             
E             At index 7 diff: 3.5 != 2.5
E             
E             Full diff:
E               [
E                   0.01,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E             -     2.5,
E             ?     ^
E             +     3.5,
E             ?     ^
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.01, 0.025,....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
  
  At index 7 diff: 3.5 != 2.5
  
  Full diff:
    [
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
  -     2.5,
  ?     ^
  +     3.5,
  ?     ^
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.54s
operator: core/NumberReplacer, occurrence: 69, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 1.5, 5.0, 10.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.01, 0.025,....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
E             
E             At index 7 diff: 1.5 != 2.5
E             
E             Full diff:
E               [
E                   0.01,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E             -     2.5,
E             ?     ^
E             +     1.5,
E             ?     ^
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.01, 0.025,....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
  
  At index 7 diff: 1.5 != 2.5
  
  Full diff:
    [
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
  -     2.5,
  ?     ^
  +     1.5,
  ?     ^
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.57s
operator: core/NumberReplacer, occurrence: 70, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 6.0, 10.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.01, 0.025,....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
E             
E             At index 8 diff: 6.0 != 5.0
E             
E             Full diff:
E               [
E                   0.01,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E             -     5.0,
E             ?     ^
E             +     6.0,
E             ?     ^
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.01, 0.025,....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
  
  At index 8 diff: 6.0 != 5.0
  
  Full diff:
    [
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
  -     5.0,
  ?     ^
  +     6.0,
  ?     ^
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.58s
operator: core/NumberReplacer, occurrence: 71, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 4.0, 10.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.01, 0.025,....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
E             
E             At index 8 diff: 4.0 != 5.0
E             
E             Full diff:
E               [
E                   0.01,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E             -     5.0,
E             ?     ^
E             +     4.0,
E             ?     ^
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.01, 0.025,....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
  
  At index 8 diff: 4.0 != 5.0
  
  Full diff:
    [
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
  -     5.0,
  ?     ^
  +     4.0,
  ?     ^
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.57s
operator: core/NumberReplacer, occurrence: 72, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 11.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.01, 0.025,....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
E             
E             At index 9 diff: 11.0 != 10.0
E             
E             Full diff:
E               [
E                   0.01,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E             -     10.0,
E             ?      ^
E             +     11.0,
E             ?      ^
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.01, 0.025,....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
  
  At index 9 diff: 11.0 != 10.0
  
  Full diff:
    [
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
  -     10.0,
  ?      ^
  +     11.0,
  ?      ^
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.58s
operator: core/NumberReplacer, occurrence: 73, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -74,7 +74,7 @@
     "stampbot_webhook_processing_duration_seconds",
     "Webhook event processing duration in seconds",
     ["event_type"],
-    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 9.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.01, 0.025,....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
E             
E             At index 9 diff: 9.0 != 10.0
E             
E             Full diff:
E               [
E                   0.01,
E                   0.025,
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E             -     10.0,
E             ?     ^^
E             +     9.0,
E             ?     ^
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.01, 0.025,....25, 0.5, ...] == [0.01, 0.025,....25, 0.5, ...]
  
  At index 9 diff: 9.0 != 10.0
  
  Full diff:
    [
        0.01,
        0.025,
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
  -     10.0,
  ?     ^^
  +     9.0,
  ?     ^
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.58s
operator: core/NumberReplacer, occurrence: 74, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -90,7 +90,7 @@
 pr_approval_duration_seconds = Histogram(
     "stampbot_pr_approval_duration_seconds",
     "PR approval operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=( 1.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 pr_dismissals_total = Counter(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:90: in <module>
    pr_approval_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 75, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -90,7 +90,7 @@
 pr_approval_duration_seconds = Histogram(
     "stampbot_pr_approval_duration_seconds",
     "PR approval operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=( -0.9, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 pr_dismissals_total = Counter(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [-0.9, 0.25, ...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 0 diff: -0.9 != 0.1
E             
E             Full diff:
E               [
E             -     0.1,
E             ?       ^
E             +     -0.9,
E             ?     +  ^
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [-0.9, 0.25, ...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 0 diff: -0.9 != 0.1
  
  Full diff:
    [
  -     0.1,
  ?       ^
  +     -0.9,
  ?     +  ^
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 76, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -90,7 +90,7 @@
 pr_approval_duration_seconds = Histogram(
     "stampbot_pr_approval_duration_seconds",
     "PR approval operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 1.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 pr_dismissals_total = Counter(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:90: in <module>
    pr_approval_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 77, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -90,7 +90,7 @@
 pr_approval_duration_seconds = Histogram(
     "stampbot_pr_approval_duration_seconds",
     "PR approval operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, -0.75, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 pr_dismissals_total = Counter(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:90: in <module>
    pr_approval_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 78, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -90,7 +90,7 @@
 pr_approval_duration_seconds = Histogram(
     "stampbot_pr_approval_duration_seconds",
     "PR approval operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 1.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 pr_dismissals_total = Counter(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:90: in <module>
    pr_approval_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.81s
operator: core/NumberReplacer, occurrence: 79, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -90,7 +90,7 @@
 pr_approval_duration_seconds = Histogram(
     "stampbot_pr_approval_duration_seconds",
     "PR approval operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, -0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 pr_dismissals_total = Counter(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:90: in <module>
    pr_approval_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 80, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -90,7 +90,7 @@
 pr_approval_duration_seconds = Histogram(
     "stampbot_pr_approval_duration_seconds",
     "PR approval operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 2.0, 2.5, 5.0, 10.0),
 )
 
 pr_dismissals_total = Counter(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.1, 0.25, 0...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 3 diff: 2.0 != 1.0
E             
E             Full diff:
E               [
E                   0.1,
E                   0.25,
E                   0.5,
E             -     1.0,
E             ?     ^
E             +     2.0,
E             ?     ^
E                   2.5,
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.1, 0.25, 0...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 3 diff: 2.0 != 1.0
  
  Full diff:
    [
        0.1,
        0.25,
        0.5,
  -     1.0,
  ?     ^
  +     2.0,
  ?     ^
        2.5,
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.57s
operator: core/NumberReplacer, occurrence: 81, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -90,7 +90,7 @@
 pr_approval_duration_seconds = Histogram(
     "stampbot_pr_approval_duration_seconds",
     "PR approval operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 0.0, 2.5, 5.0, 10.0),
 )
 
 pr_dismissals_total = Counter(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:90: in <module>
    pr_approval_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 82, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -90,7 +90,7 @@
 pr_approval_duration_seconds = Histogram(
     "stampbot_pr_approval_duration_seconds",
     "PR approval operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 1.0, 3.5, 5.0, 10.0),
 )
 
 pr_dismissals_total = Counter(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.1, 0.25, 0...3.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 4 diff: 3.5 != 2.5
E             
E             Full diff:
E               [
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E             -     2.5,
E             ?     ^
E             +     3.5,
E             ?     ^
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.1, 0.25, 0...3.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 4 diff: 3.5 != 2.5
  
  Full diff:
    [
        0.1,
        0.25,
        0.5,
        1.0,
  -     2.5,
  ?     ^
  +     3.5,
  ?     ^
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 83, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -90,7 +90,7 @@
 pr_approval_duration_seconds = Histogram(
     "stampbot_pr_approval_duration_seconds",
     "PR approval operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 1.0, 1.5, 5.0, 10.0),
 )
 
 pr_dismissals_total = Counter(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.1, 0.25, 0...1.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 4 diff: 1.5 != 2.5
E             
E             Full diff:
E               [
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E             -     2.5,
E             ?     ^
E             +     1.5,
E             ?     ^
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.1, 0.25, 0...1.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 4 diff: 1.5 != 2.5
  
  Full diff:
    [
        0.1,
        0.25,
        0.5,
        1.0,
  -     2.5,
  ?     ^
  +     1.5,
  ?     ^
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 84, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -90,7 +90,7 @@
 pr_approval_duration_seconds = Histogram(
     "stampbot_pr_approval_duration_seconds",
     "PR approval operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 6.0, 10.0),
 )
 
 pr_dismissals_total = Counter(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.1, 0.25, 0...2.5, 6.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 5 diff: 6.0 != 5.0
E             
E             Full diff:
E               [
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E             -     5.0,
E             ?     ^
E             +     6.0,
E             ?     ^
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.1, 0.25, 0...2.5, 6.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 5 diff: 6.0 != 5.0
  
  Full diff:
    [
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
  -     5.0,
  ?     ^
  +     6.0,
  ?     ^
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.57s
operator: core/NumberReplacer, occurrence: 85, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -90,7 +90,7 @@
 pr_approval_duration_seconds = Histogram(
     "stampbot_pr_approval_duration_seconds",
     "PR approval operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 4.0, 10.0),
 )
 
 pr_dismissals_total = Counter(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.1, 0.25, 0...2.5, 4.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 5 diff: 4.0 != 5.0
E             
E             Full diff:
E               [
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E             -     5.0,
E             ?     ^
E             +     4.0,
E             ?     ^
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.1, 0.25, 0...2.5, 4.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 5 diff: 4.0 != 5.0
  
  Full diff:
    [
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
  -     5.0,
  ?     ^
  +     4.0,
  ?     ^
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 86, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -90,7 +90,7 @@
 pr_approval_duration_seconds = Histogram(
     "stampbot_pr_approval_duration_seconds",
     "PR approval operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 11.0),
 )
 
 pr_dismissals_total = Counter(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.1, 0.25, 0...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 6 diff: 11.0 != 10.0
E             
E             Full diff:
E               [
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E             -     10.0,
E             ?      ^
E             +     11.0,
E             ?      ^
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.1, 0.25, 0...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 6 diff: 11.0 != 10.0
  
  Full diff:
    [
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
  -     10.0,
  ?      ^
  +     11.0,
  ?      ^
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 87, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -90,7 +90,7 @@
 pr_approval_duration_seconds = Histogram(
     "stampbot_pr_approval_duration_seconds",
     "PR approval operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 9.0),
 )
 
 pr_dismissals_total = Counter(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.1, 0.25, 0...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 6 diff: 9.0 != 10.0
E             
E             Full diff:
E               [
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E             -     10.0,
E             ?     ^^
E             +     9.0,
E             ?     ^
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.1, 0.25, 0...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 6 diff: 9.0 != 10.0
  
  Full diff:
    [
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
  -     10.0,
  ?     ^^
  +     9.0,
  ?     ^
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.54s
operator: core/NumberReplacer, occurrence: 88, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -102,7 +102,7 @@
 pr_dismissal_duration_seconds = Histogram(
     "stampbot_pr_dismissal_duration_seconds",
     "PR dismissal operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=( 1.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:102: in <module>
    pr_dismissal_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 89, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -102,7 +102,7 @@
 pr_dismissal_duration_seconds = Histogram(
     "stampbot_pr_dismissal_duration_seconds",
     "PR dismissal operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=( -0.9, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [-0.9, 0.25, ...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 0 diff: -0.9 != 0.1
E             
E             Full diff:
E               [
E             -     0.1,
E             ?       ^
E             +     -0.9,
E             ?     +  ^
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [-0.9, 0.25, ...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 0 diff: -0.9 != 0.1
  
  Full diff:
    [
  -     0.1,
  ?       ^
  +     -0.9,
  ?     +  ^
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 90, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -102,7 +102,7 @@
 pr_dismissal_duration_seconds = Histogram(
     "stampbot_pr_dismissal_duration_seconds",
     "PR dismissal operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 1.25, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:102: in <module>
    pr_dismissal_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 91, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -102,7 +102,7 @@
 pr_dismissal_duration_seconds = Histogram(
     "stampbot_pr_dismissal_duration_seconds",
     "PR dismissal operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, -0.75, 0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:102: in <module>
    pr_dismissal_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 92, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -102,7 +102,7 @@
 pr_dismissal_duration_seconds = Histogram(
     "stampbot_pr_dismissal_duration_seconds",
     "PR dismissal operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 1.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:102: in <module>
    pr_dismissal_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 93, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -102,7 +102,7 @@
 pr_dismissal_duration_seconds = Histogram(
     "stampbot_pr_dismissal_duration_seconds",
     "PR dismissal operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, -0.5, 1.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:102: in <module>
    pr_dismissal_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 94, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -102,7 +102,7 @@
 pr_dismissal_duration_seconds = Histogram(
     "stampbot_pr_dismissal_duration_seconds",
     "PR dismissal operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 2.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.1, 0.25, 0...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 3 diff: 2.0 != 1.0
E             
E             Full diff:
E               [
E                   0.1,
E                   0.25,
E                   0.5,
E             -     1.0,
E             ?     ^
E             +     2.0,
E             ?     ^
E                   2.5,
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.1, 0.25, 0...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 3 diff: 2.0 != 1.0
  
  Full diff:
    [
        0.1,
        0.25,
        0.5,
  -     1.0,
  ?     ^
  +     2.0,
  ?     ^
        2.5,
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 95, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -102,7 +102,7 @@
 pr_dismissal_duration_seconds = Histogram(
     "stampbot_pr_dismissal_duration_seconds",
     "PR dismissal operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 0.0, 2.5, 5.0, 10.0),
 )
 
 # =============================================================================
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:102: in <module>
    pr_dismissal_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 96, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -102,7 +102,7 @@
 pr_dismissal_duration_seconds = Histogram(
     "stampbot_pr_dismissal_duration_seconds",
     "PR dismissal operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 1.0, 3.5, 5.0, 10.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.1, 0.25, 0...3.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 4 diff: 3.5 != 2.5
E             
E             Full diff:
E               [
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E             -     2.5,
E             ?     ^
E             +     3.5,
E             ?     ^
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.1, 0.25, 0...3.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 4 diff: 3.5 != 2.5
  
  Full diff:
    [
        0.1,
        0.25,
        0.5,
        1.0,
  -     2.5,
  ?     ^
  +     3.5,
  ?     ^
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 97, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -102,7 +102,7 @@
 pr_dismissal_duration_seconds = Histogram(
     "stampbot_pr_dismissal_duration_seconds",
     "PR dismissal operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 1.0, 1.5, 5.0, 10.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.1, 0.25, 0...1.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 4 diff: 1.5 != 2.5
E             
E             Full diff:
E               [
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E             -     2.5,
E             ?     ^
E             +     1.5,
E             ?     ^
E                   5.0,
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.1, 0.25, 0...1.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 4 diff: 1.5 != 2.5
  
  Full diff:
    [
        0.1,
        0.25,
        0.5,
        1.0,
  -     2.5,
  ?     ^
  +     1.5,
  ?     ^
        5.0,
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 98, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -102,7 +102,7 @@
 pr_dismissal_duration_seconds = Histogram(
     "stampbot_pr_dismissal_duration_seconds",
     "PR dismissal operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 6.0, 10.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.1, 0.25, 0...2.5, 6.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 5 diff: 6.0 != 5.0
E             
E             Full diff:
E               [
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E             -     5.0,
E             ?     ^
E             +     6.0,
E             ?     ^
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.1, 0.25, 0...2.5, 6.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 5 diff: 6.0 != 5.0
  
  Full diff:
    [
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
  -     5.0,
  ?     ^
  +     6.0,
  ?     ^
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 99, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -102,7 +102,7 @@
 pr_dismissal_duration_seconds = Histogram(
     "stampbot_pr_dismissal_duration_seconds",
     "PR dismissal operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 4.0, 10.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.1, 0.25, 0...2.5, 4.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 5 diff: 4.0 != 5.0
E             
E             Full diff:
E               [
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E             -     5.0,
E             ?     ^
E             +     4.0,
E             ?     ^
E                   10.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.1, 0.25, 0...2.5, 4.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 5 diff: 4.0 != 5.0
  
  Full diff:
    [
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
  -     5.0,
  ?     ^
  +     4.0,
  ?     ^
        10.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.59s
operator: core/NumberReplacer, occurrence: 100, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -102,7 +102,7 @@
 pr_dismissal_duration_seconds = Histogram(
     "stampbot_pr_dismissal_duration_seconds",
     "PR dismissal operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 11.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.1, 0.25, 0...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 6 diff: 11.0 != 10.0
E             
E             Full diff:
E               [
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E             -     10.0,
E             ?      ^
E             +     11.0,
E             ?      ^
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.1, 0.25, 0...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 6 diff: 11.0 != 10.0
  
  Full diff:
    [
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
  -     10.0,
  ?      ^
  +     11.0,
  ?      ^
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.54s
operator: core/NumberReplacer, occurrence: 101, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -102,7 +102,7 @@
 pr_dismissal_duration_seconds = Histogram(
     "stampbot_pr_dismissal_duration_seconds",
     "PR dismissal operation duration in seconds",
-    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
+    buckets=(0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 9.0),
 )
 
 # =============================================================================
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.1, 0.25, 0...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
E             
E             At index 6 diff: 9.0 != 10.0
E             
E             Full diff:
E               [
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E             -     10.0,
E             ?     ^^
E             +     9.0,
E             ?     ^
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.1, 0.25, 0...2.5, 5.0, ...] == [0.1, 0.25, 0...2.5, 5.0, ...]
  
  At index 6 diff: 9.0 != 10.0
  
  Full diff:
    [
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
  -     10.0,
  ?     ^^
  +     9.0,
  ?     ^
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.60s
operator: core/NumberReplacer, occurrence: 102, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=( 1.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:131: in <module>
    github_api_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 103, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=( -0.95, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [-0.95, 0.1, ...1.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
E             
E             At index 0 diff: -0.95 != 0.05
E             
E             Full diff:
E               [
E             -     0.05,
E             ?       ^
E             +     -0.95,
E             ?     +  ^
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E                   10.0,
E                   30.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [-0.95, 0.1, ...1.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
  
  At index 0 diff: -0.95 != 0.05
  
  Full diff:
    [
  -     0.05,
  ?       ^
  +     -0.95,
  ?     +  ^
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
        10.0,
        30.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 104, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, 1.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:131: in <module>
    github_api_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.83s
operator: core/NumberReplacer, occurrence: 105, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, -0.9, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:131: in <module>
    github_api_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.81s
operator: core/NumberReplacer, occurrence: 106, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, 0.1, 1.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:131: in <module>
    github_api_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.79s
operator: core/NumberReplacer, occurrence: 107, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, 0.1, -0.75, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:131: in <module>
    github_api_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.81s
operator: core/NumberReplacer, occurrence: 108, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, 0.1, 0.25, 1.5, 1.0, 2.5, 5.0, 10.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:131: in <module>
    github_api_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 109, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, 0.1, 0.25, -0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:131: in <module>
    github_api_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 110, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, 0.1, 0.25, 0.5, 2.0, 2.5, 5.0, 10.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.05, 0.1, 0...2.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
E             
E             At index 4 diff: 2.0 != 1.0
E             
E             Full diff:
E               [
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E             -     1.0,
E             ?     ^
E             +     2.0,
E             ?     ^
E                   2.5,
E                   5.0,
E                   10.0,
E                   30.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.05, 0.1, 0...2.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
  
  At index 4 diff: 2.0 != 1.0
  
  Full diff:
    [
        0.05,
        0.1,
        0.25,
        0.5,
  -     1.0,
  ?     ^
  +     2.0,
  ?     ^
        2.5,
        5.0,
        10.0,
        30.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.61s
operator: core/NumberReplacer, occurrence: 111, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, 0.1, 0.25, 0.5, 0.0, 2.5, 5.0, 10.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_metrics.py ____________________
tests/test_metrics.py:10: in <module>
    from stampbot import metrics
stampbot/metrics.py:131: in <module>
    github_api_request_duration_seconds = Histogram(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:625: in __init__
    self._prepare_buckets(buckets)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/prometheus_client/metrics.py:643: in _prepare_buckets
    raise ValueError('Buckets not in sorted order')
E   ValueError: Buckets not in sorted order
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_metrics.py - ValueError: Buckets not in sorted order
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.80s
operator: core/NumberReplacer, occurrence: 112, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 3.5, 5.0, 10.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.05, 0.1, 0...1.0, 3.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
E             
E             At index 5 diff: 3.5 != 2.5
E             
E             Full diff:
E               [
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E             -     2.5,
E             ?     ^
E             +     3.5,
E             ?     ^
E                   5.0,
E                   10.0,
E                   30.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.05, 0.1, 0...1.0, 3.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
  
  At index 5 diff: 3.5 != 2.5
  
  Full diff:
    [
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
  -     2.5,
  ?     ^
  +     3.5,
  ?     ^
        5.0,
        10.0,
        30.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.54s
operator: core/NumberReplacer, occurrence: 113, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 1.5, 5.0, 10.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.05, 0.1, 0...1.0, 1.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
E             
E             At index 5 diff: 1.5 != 2.5
E             
E             Full diff:
E               [
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E             -     2.5,
E             ?     ^
E             +     1.5,
E             ?     ^
E                   5.0,
E                   10.0,
E                   30.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.05, 0.1, 0...1.0, 1.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
  
  At index 5 diff: 1.5 != 2.5
  
  Full diff:
    [
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
  -     2.5,
  ?     ^
  +     1.5,
  ?     ^
        5.0,
        10.0,
        30.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.54s
operator: core/NumberReplacer, occurrence: 114, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 6.0, 10.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.05, 0.1, 0...1.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
E             
E             At index 6 diff: 6.0 != 5.0
E             
E             Full diff:
E               [
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E             -     5.0,
E             ?     ^
E             +     6.0,
E             ?     ^
E                   10.0,
E                   30.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.05, 0.1, 0...1.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
  
  At index 6 diff: 6.0 != 5.0
  
  Full diff:
    [
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
  -     5.0,
  ?     ^
  +     6.0,
  ?     ^
        10.0,
        30.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 115, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 4.0, 10.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.05, 0.1, 0...1.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
E             
E             At index 6 diff: 4.0 != 5.0
E             
E             Full diff:
E               [
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E             -     5.0,
E             ?     ^
E             +     4.0,
E             ?     ^
E                   10.0,
E                   30.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.05, 0.1, 0...1.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
  
  At index 6 diff: 4.0 != 5.0
  
  Full diff:
    [
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
  -     5.0,
  ?     ^
  +     4.0,
  ?     ^
        10.0,
        30.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 116, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 11.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.05, 0.1, 0...1.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
E             
E             At index 7 diff: 11.0 != 10.0
E             
E             Full diff:
E               [
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E             -     10.0,
E             ?      ^
E             +     11.0,
E             ?      ^
E                   30.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.05, 0.1, 0...1.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
  
  At index 7 diff: 11.0 != 10.0
  
  Full diff:
    [
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
  -     10.0,
  ?      ^
  +     11.0,
  ?      ^
        30.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.57s
operator: core/NumberReplacer, occurrence: 117, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 9.0, 30.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.05, 0.1, 0...1.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
E             
E             At index 7 diff: 9.0 != 10.0
E             
E             Full diff:
E               [
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E             -     10.0,
E             ?     ^^
E             +     9.0,
E             ?     ^
E                   30.0,
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.05, 0.1, 0...1.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
  
  At index 7 diff: 9.0 != 10.0
  
  Full diff:
    [
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
  -     10.0,
  ?     ^^
  +     9.0,
  ?     ^
        30.0,
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.57s
operator: core/NumberReplacer, occurrence: 118, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 31.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.05, 0.1, 0...1.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
E             
E             At index 8 diff: 31.0 != 30.0
E             
E             Full diff:
E               [
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E                   10.0,
E             -     30.0,
E             ?      ^
E             +     31.0,
E             ?      ^
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.05, 0.1, 0...1.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
  
  At index 8 diff: 31.0 != 30.0
  
  Full diff:
    [
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
        10.0,
  -     30.0,
  ?      ^
  +     31.0,
  ?      ^
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 119, definition_name: None
--- mutation diff ---
--- astampbot/metrics.py
+++ bstampbot/metrics.py
@@ -132,7 +132,7 @@
     "stampbot_github_api_request_duration_seconds",
     "GitHub API request duration in seconds",
     ["operation"],
-    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
+    buckets=(0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 29.0),
 )
 
 github_api_rate_limit_remaining = Gauge(
........................................................................ [ 30%]
.....................................................................F
=================================== FAILURES ===================================
___________________________ test_histogram_contracts ___________________________

    def test_histogram_contracts():
        """Test histogram names, labels, and bucket boundaries."""
        expected_histograms = {
            "http_request_duration_seconds": {
                "name": "stampbot_http_request_duration_seconds",
                "labels": ("method", "endpoint"),
                "buckets": (0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "http_request_size_bytes": {
                "name": "stampbot_http_request_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "http_response_size_bytes": {
                "name": "stampbot_http_response_size_bytes",
                "labels": ("method", "endpoint"),
                "buckets": (100, 500, 1000, 5000, 10000, 50000, 100000, 500000),
            },
            "webhook_processing_duration_seconds": {
                "name": "stampbot_webhook_processing_duration_seconds",
                "labels": ("event_type",),
                "buckets": (0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_approval_duration_seconds": {
                "name": "stampbot_pr_approval_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "pr_dismissal_duration_seconds": {
                "name": "stampbot_pr_dismissal_duration_seconds",
                "labels": (),
                "buckets": (0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0),
            },
            "github_api_request_duration_seconds": {
                "name": "stampbot_github_api_request_duration_seconds",
                "labels": ("operation",),
                "buckets": (0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0),
            },
        }
    
        for attribute, expected in expected_histograms.items():
            histogram = getattr(metrics, attribute)
    
            assert isinstance(histogram, Histogram)
            assert histogram._name == expected["name"]
            assert histogram._labelnames == expected["labels"]
>           assert histogram._upper_bounds == [*expected["buckets"], math.inf]
E           assert [0.05, 0.1, 0...1.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
E             
E             At index 8 diff: 29.0 != 30.0
E             
E             Full diff:
E               [
E                   0.05,
E                   0.1,
E                   0.25,
E                   0.5,
E                   1.0,
E                   2.5,
E                   5.0,
E                   10.0,
E             -     30.0,
E             ?     ^^
E             +     29.0,
E             ?     ^^
E                   inf,
E               ]

tests/test_metrics.py:59: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_metrics.py::test_histogram_contracts - assert [0.05, 0.1, 0...1.0, 2.5, ...] == [0.05, 0.1, 0...1.0, 2.5, ...]
  
  At index 8 diff: 29.0 != 30.0
  
  Full diff:
    [
        0.05,
        0.1,
        0.25,
        0.5,
        1.0,
        2.5,
        5.0,
        10.0,
  -     30.0,
  ?     ^^
  +     29.0,
  ?     ^^
        inf,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 141 passed, 3 deselected, 1 warning in 2.56s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 0, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -33,7 +33,7 @@
     """
     log_format = settings.log_format.lower()
 
-    if log_format == "json":
+    if log_format != "json":
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
         return structlog.dev.ConsoleRenderer(colors=True)
........................................................................ [ 30%]
..................F
=================================== FAILURES ===================================
________________________ test_get_log_renderer_console _________________________

    def test_get_log_renderer_console():
        """Test console renderer selection."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "console"
            from stampbot.logger import _get_log_renderer
    
            renderer = _get_log_renderer()
>           assert isinstance(renderer, structlog.dev.ConsoleRenderer)
E           AssertionError: assert False
E            +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7fdb3a694a50>, <class 'structlog.dev.ConsoleRenderer'>)
E            +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
E            +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev

tests/test_logger.py:46: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_console - AssertionError: assert False
 +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7fdb3a694a50>, <class 'structlog.dev.ConsoleRenderer'>)
 +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
 +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 90 passed, 3 deselected, 1 warning in 2.18s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 1, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -35,7 +35,7 @@
 
     if log_format == "json":
         return structlog.processors.JSONRenderer()
-    elif log_format == "console":
+    elif log_format != "console":
         return structlog.dev.ConsoleRenderer(colors=True)
     elif log_format == "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
........................................................................ [ 30%]
..................F
=================================== FAILURES ===================================
________________________ test_get_log_renderer_console _________________________

    def test_get_log_renderer_console():
        """Test console renderer selection."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "console"
            from stampbot.logger import _get_log_renderer
    
            renderer = _get_log_renderer()
>           assert isinstance(renderer, structlog.dev.ConsoleRenderer)
E           AssertionError: assert False
E            +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f5bbdeb8a50>, <class 'structlog.dev.ConsoleRenderer'>)
E            +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
E            +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev

tests/test_logger.py:46: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_console - AssertionError: assert False
 +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f5bbdeb8a50>, <class 'structlog.dev.ConsoleRenderer'>)
 +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
 +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 90 passed, 3 deselected, 1 warning in 2.16s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 2, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -37,7 +37,7 @@
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
         return structlog.dev.ConsoleRenderer(colors=True)
-    elif log_format == "auto":
+    elif log_format != "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
         if is_running_in_kubernetes():
             return structlog.processors.JSONRenderer()
........................................................................ [ 30%]
....................F
=================================== FAILURES ===================================
_______________________ test_get_log_renderer_auto_local _______________________

    def test_get_log_renderer_auto_local():
        """Test auto renderer in local environment."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "auto"
            with patch("stampbot.logger.is_running_in_kubernetes", return_value=False):
                from stampbot.logger import _get_log_renderer
    
                renderer = _get_log_renderer()
>               assert isinstance(renderer, structlog.dev.ConsoleRenderer)
E               AssertionError: assert False
E                +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f47c63c0690>, <class 'structlog.dev.ConsoleRenderer'>)
E                +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
E                +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev

tests/test_logger.py:68: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_auto_local - AssertionError: assert False
 +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f47c63c0690>, <class 'structlog.dev.ConsoleRenderer'>)
 +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
 +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 92 passed, 3 deselected, 1 warning in 2.18s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 0, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -33,7 +33,7 @@
     """
     log_format = settings.log_format.lower()
 
-    if log_format == "json":
+    if log_format < "json":
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
         return structlog.dev.ConsoleRenderer(colors=True)
........................................................................ [ 30%]
..................F
=================================== FAILURES ===================================
________________________ test_get_log_renderer_console _________________________

    def test_get_log_renderer_console():
        """Test console renderer selection."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "console"
            from stampbot.logger import _get_log_renderer
    
            renderer = _get_log_renderer()
>           assert isinstance(renderer, structlog.dev.ConsoleRenderer)
E           AssertionError: assert False
E            +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7ff7c59c0a50>, <class 'structlog.dev.ConsoleRenderer'>)
E            +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
E            +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev

tests/test_logger.py:46: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_console - AssertionError: assert False
 +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7ff7c59c0a50>, <class 'structlog.dev.ConsoleRenderer'>)
 +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
 +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 90 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 1, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -35,7 +35,7 @@
 
     if log_format == "json":
         return structlog.processors.JSONRenderer()
-    elif log_format == "console":
+    elif log_format < "console":
         return structlog.dev.ConsoleRenderer(colors=True)
     elif log_format == "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
........................................................................ [ 30%]
..................F
=================================== FAILURES ===================================
________________________ test_get_log_renderer_console _________________________

    def test_get_log_renderer_console():
        """Test console renderer selection."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "console"
            from stampbot.logger import _get_log_renderer
    
            renderer = _get_log_renderer()
>           assert isinstance(renderer, structlog.dev.ConsoleRenderer)
E           AssertionError: assert False
E            +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f4b5f3c8a50>, <class 'structlog.dev.ConsoleRenderer'>)
E            +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
E            +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev

tests/test_logger.py:46: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_console - AssertionError: assert False
 +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f4b5f3c8a50>, <class 'structlog.dev.ConsoleRenderer'>)
 +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
 +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 90 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 2, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -37,7 +37,7 @@
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
         return structlog.dev.ConsoleRenderer(colors=True)
-    elif log_format == "auto":
+    elif log_format < "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
         if is_running_in_kubernetes():
             return structlog.processors.JSONRenderer()
........................................................................ [ 30%]
....................F
=================================== FAILURES ===================================
_______________________ test_get_log_renderer_auto_local _______________________

    def test_get_log_renderer_auto_local():
        """Test auto renderer in local environment."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "auto"
            with patch("stampbot.logger.is_running_in_kubernetes", return_value=False):
                from stampbot.logger import _get_log_renderer
    
                renderer = _get_log_renderer()
>               assert isinstance(renderer, structlog.dev.ConsoleRenderer)
E               AssertionError: assert False
E                +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7fe3285a4690>, <class 'structlog.dev.ConsoleRenderer'>)
E                +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
E                +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev

tests/test_logger.py:68: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_auto_local - AssertionError: assert False
 +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7fe3285a4690>, <class 'structlog.dev.ConsoleRenderer'>)
 +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
 +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 92 passed, 3 deselected, 1 warning in 2.22s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 0, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -33,7 +33,7 @@
     """
     log_format = settings.log_format.lower()
 
-    if log_format == "json":
+    if log_format <= "json":
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
         return structlog.dev.ConsoleRenderer(colors=True)
........................................................................ [ 30%]
..................F
=================================== FAILURES ===================================
________________________ test_get_log_renderer_console _________________________

    def test_get_log_renderer_console():
        """Test console renderer selection."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "console"
            from stampbot.logger import _get_log_renderer
    
            renderer = _get_log_renderer()
>           assert isinstance(renderer, structlog.dev.ConsoleRenderer)
E           AssertionError: assert False
E            +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f9ff9de8a50>, <class 'structlog.dev.ConsoleRenderer'>)
E            +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
E            +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev

tests/test_logger.py:46: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_console - AssertionError: assert False
 +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f9ff9de8a50>, <class 'structlog.dev.ConsoleRenderer'>)
 +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
 +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 90 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 1, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -35,7 +35,7 @@
 
     if log_format == "json":
         return structlog.processors.JSONRenderer()
-    elif log_format == "console":
+    elif log_format <= "console":
         return structlog.dev.ConsoleRenderer(colors=True)
     elif log_format == "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
........................................................................ [ 30%]
...................F
=================================== FAILURES ===================================
____________________ test_get_log_renderer_auto_kubernetes _____________________

    def test_get_log_renderer_auto_kubernetes():
        """Test auto renderer in Kubernetes environment."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "auto"
            with patch("stampbot.logger.is_running_in_kubernetes", return_value=True):
                from stampbot.logger import _get_log_renderer
    
                renderer = _get_log_renderer()
>               assert isinstance(renderer, structlog.processors.JSONRenderer)
E               AssertionError: assert False
E                +  where False = isinstance(<structlog.dev.ConsoleRenderer object at 0x7f43387a0690>, <class 'structlog.processors.JSONRenderer'>)
E                +    where <class 'structlog.processors.JSONRenderer'> = <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'>.JSONRenderer
E                +      where <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'> = structlog.processors

tests/test_logger.py:57: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_auto_kubernetes - AssertionError: assert False
 +  where False = isinstance(<structlog.dev.ConsoleRenderer object at 0x7f43387a0690>, <class 'structlog.processors.JSONRenderer'>)
 +    where <class 'structlog.processors.JSONRenderer'> = <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'>.JSONRenderer
 +      where <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'> = structlog.processors
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 91 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 2, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -37,7 +37,7 @@
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
         return structlog.dev.ConsoleRenderer(colors=True)
-    elif log_format == "auto":
+    elif log_format <= "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
         if is_running_in_kubernetes():
             return structlog.processors.JSONRenderer()
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 0, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -33,7 +33,7 @@
     """
     log_format = settings.log_format.lower()
 
-    if log_format == "json":
+    if log_format > "json":
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
         return structlog.dev.ConsoleRenderer(colors=True)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.27s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 1, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -35,7 +35,7 @@
 
     if log_format == "json":
         return structlog.processors.JSONRenderer()
-    elif log_format == "console":
+    elif log_format > "console":
         return structlog.dev.ConsoleRenderer(colors=True)
     elif log_format == "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
........................................................................ [ 30%]
..................F
=================================== FAILURES ===================================
________________________ test_get_log_renderer_console _________________________

    def test_get_log_renderer_console():
        """Test console renderer selection."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "console"
            from stampbot.logger import _get_log_renderer
    
            renderer = _get_log_renderer()
>           assert isinstance(renderer, structlog.dev.ConsoleRenderer)
E           AssertionError: assert False
E            +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f64b5b84a50>, <class 'structlog.dev.ConsoleRenderer'>)
E            +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
E            +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev

tests/test_logger.py:46: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_console - AssertionError: assert False
 +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f64b5b84a50>, <class 'structlog.dev.ConsoleRenderer'>)
 +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
 +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 90 passed, 3 deselected, 1 warning in 2.16s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 2, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -37,7 +37,7 @@
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
         return structlog.dev.ConsoleRenderer(colors=True)
-    elif log_format == "auto":
+    elif log_format > "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
         if is_running_in_kubernetes():
             return structlog.processors.JSONRenderer()
........................................................................ [ 30%]
....................F
=================================== FAILURES ===================================
_______________________ test_get_log_renderer_auto_local _______________________

    def test_get_log_renderer_auto_local():
        """Test auto renderer in local environment."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "auto"
            with patch("stampbot.logger.is_running_in_kubernetes", return_value=False):
                from stampbot.logger import _get_log_renderer
    
                renderer = _get_log_renderer()
>               assert isinstance(renderer, structlog.dev.ConsoleRenderer)
E               AssertionError: assert False
E                +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f6ee40cc690>, <class 'structlog.dev.ConsoleRenderer'>)
E                +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
E                +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev

tests/test_logger.py:68: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_auto_local - AssertionError: assert False
 +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f6ee40cc690>, <class 'structlog.dev.ConsoleRenderer'>)
 +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
 +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 92 passed, 3 deselected, 1 warning in 2.19s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 0, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -33,7 +33,7 @@
     """
     log_format = settings.log_format.lower()
 
-    if log_format == "json":
+    if log_format >= "json":
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
         return structlog.dev.ConsoleRenderer(colors=True)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 1, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -35,7 +35,7 @@
 
     if log_format == "json":
         return structlog.processors.JSONRenderer()
-    elif log_format == "console":
+    elif log_format >= "console":
         return structlog.dev.ConsoleRenderer(colors=True)
     elif log_format == "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
........................................................................ [ 30%]
.....................F
=================================== FAILURES ===================================
_____________________ test_get_log_renderer_unknown_format _____________________

    def test_get_log_renderer_unknown_format():
        """Test fallback to JSON for unknown format."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "unknown_format"
            from stampbot.logger import _get_log_renderer
    
            renderer = _get_log_renderer()
>           assert isinstance(renderer, structlog.processors.JSONRenderer)
E           AssertionError: assert False
E            +  where False = isinstance(<structlog.dev.ConsoleRenderer object at 0x7f7a49d2ac40>, <class 'structlog.processors.JSONRenderer'>)
E            +    where <class 'structlog.processors.JSONRenderer'> = <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'>.JSONRenderer
E            +      where <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'> = structlog.processors

tests/test_logger.py:78: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_unknown_format - AssertionError: assert False
 +  where False = isinstance(<structlog.dev.ConsoleRenderer object at 0x7f7a49d2ac40>, <class 'structlog.processors.JSONRenderer'>)
 +    where <class 'structlog.processors.JSONRenderer'> = <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'>.JSONRenderer
 +      where <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'> = structlog.processors
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 93 passed, 3 deselected, 1 warning in 2.26s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 2, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -37,7 +37,7 @@
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
         return structlog.dev.ConsoleRenderer(colors=True)
-    elif log_format == "auto":
+    elif log_format >= "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
         if is_running_in_kubernetes():
             return structlog.processors.JSONRenderer()
........................................................................ [ 30%]
.....................F
=================================== FAILURES ===================================
_____________________ test_get_log_renderer_unknown_format _____________________

    def test_get_log_renderer_unknown_format():
        """Test fallback to JSON for unknown format."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "unknown_format"
            from stampbot.logger import _get_log_renderer
    
            renderer = _get_log_renderer()
>           assert isinstance(renderer, structlog.processors.JSONRenderer)
E           AssertionError: assert False
E            +  where False = isinstance(<structlog.dev.ConsoleRenderer object at 0x7f15a6b76c40>, <class 'structlog.processors.JSONRenderer'>)
E            +    where <class 'structlog.processors.JSONRenderer'> = <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'>.JSONRenderer
E            +      where <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'> = structlog.processors

tests/test_logger.py:78: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_unknown_format - AssertionError: assert False
 +  where False = isinstance(<structlog.dev.ConsoleRenderer object at 0x7f15a6b76c40>, <class 'structlog.processors.JSONRenderer'>)
 +    where <class 'structlog.processors.JSONRenderer'> = <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'>.JSONRenderer
 +      where <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'> = structlog.processors
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 93 passed, 3 deselected, 1 warning in 2.20s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 0, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -33,7 +33,7 @@
     """
     log_format = settings.log_format.lower()
 
-    if log_format == "json":
+    if log_format is "json":
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
         return structlog.dev.ConsoleRenderer(colors=True)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

stampbot/logger.py:36
  /home/runner/work/stampbot/stampbot/stampbot/logger.py:36: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    if log_format is "json":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 2 warnings in 3.24s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 1, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -35,7 +35,7 @@
 
     if log_format == "json":
         return structlog.processors.JSONRenderer()
-    elif log_format == "console":
+    elif log_format is "console":
         return structlog.dev.ConsoleRenderer(colors=True)
     elif log_format == "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
........................................................................ [ 30%]
..................F
=================================== FAILURES ===================================
________________________ test_get_log_renderer_console _________________________

    def test_get_log_renderer_console():
        """Test console renderer selection."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "console"
            from stampbot.logger import _get_log_renderer
    
            renderer = _get_log_renderer()
>           assert isinstance(renderer, structlog.dev.ConsoleRenderer)
E           AssertionError: assert False
E            +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f7fecd88cd0>, <class 'structlog.dev.ConsoleRenderer'>)
E            +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
E            +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev

tests/test_logger.py:46: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

stampbot/logger.py:38
  /home/runner/work/stampbot/stampbot/stampbot/logger.py:38: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    elif log_format is "console":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_console - AssertionError: assert False
 +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f7fecd88cd0>, <class 'structlog.dev.ConsoleRenderer'>)
 +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
 +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 90 passed, 3 deselected, 2 warnings in 2.15s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 2, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -37,7 +37,7 @@
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
         return structlog.dev.ConsoleRenderer(colors=True)
-    elif log_format == "auto":
+    elif log_format is "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
         if is_running_in_kubernetes():
             return structlog.processors.JSONRenderer()
........................................................................ [ 30%]
....................F
=================================== FAILURES ===================================
_______________________ test_get_log_renderer_auto_local _______________________

    def test_get_log_renderer_auto_local():
        """Test auto renderer in local environment."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "auto"
            with patch("stampbot.logger.is_running_in_kubernetes", return_value=False):
                from stampbot.logger import _get_log_renderer
    
                renderer = _get_log_renderer()
>               assert isinstance(renderer, structlog.dev.ConsoleRenderer)
E               AssertionError: assert False
E                +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f46ba9ec910>, <class 'structlog.dev.ConsoleRenderer'>)
E                +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
E                +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev

tests/test_logger.py:68: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

stampbot/logger.py:40
  /home/runner/work/stampbot/stampbot/stampbot/logger.py:40: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    elif log_format is "auto":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_auto_local - AssertionError: assert False
 +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f46ba9ec910>, <class 'structlog.dev.ConsoleRenderer'>)
 +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
 +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 92 passed, 3 deselected, 2 warnings in 2.16s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 0, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -33,7 +33,7 @@
     """
     log_format = settings.log_format.lower()
 
-    if log_format == "json":
+    if log_format is not "json":
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
         return structlog.dev.ConsoleRenderer(colors=True)
........................................................................ [ 30%]
..................F
=================================== FAILURES ===================================
________________________ test_get_log_renderer_console _________________________

    def test_get_log_renderer_console():
        """Test console renderer selection."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "console"
            from stampbot.logger import _get_log_renderer
    
            renderer = _get_log_renderer()
>           assert isinstance(renderer, structlog.dev.ConsoleRenderer)
E           AssertionError: assert False
E            +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f5bebdbccd0>, <class 'structlog.dev.ConsoleRenderer'>)
E            +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
E            +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev

tests/test_logger.py:46: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

stampbot/logger.py:36
  /home/runner/work/stampbot/stampbot/stampbot/logger.py:36: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    if log_format is not "json":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_console - AssertionError: assert False
 +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f5bebdbccd0>, <class 'structlog.dev.ConsoleRenderer'>)
 +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
 +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 90 passed, 3 deselected, 2 warnings in 2.18s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 1, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -35,7 +35,7 @@
 
     if log_format == "json":
         return structlog.processors.JSONRenderer()
-    elif log_format == "console":
+    elif log_format is not "console":
         return structlog.dev.ConsoleRenderer(colors=True)
     elif log_format == "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
........................................................................ [ 30%]
...................F
=================================== FAILURES ===================================
____________________ test_get_log_renderer_auto_kubernetes _____________________

    def test_get_log_renderer_auto_kubernetes():
        """Test auto renderer in Kubernetes environment."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "auto"
            with patch("stampbot.logger.is_running_in_kubernetes", return_value=True):
                from stampbot.logger import _get_log_renderer
    
                renderer = _get_log_renderer()
>               assert isinstance(renderer, structlog.processors.JSONRenderer)
E               AssertionError: assert False
E                +  where False = isinstance(<structlog.dev.ConsoleRenderer object at 0x7f2a3dab4910>, <class 'structlog.processors.JSONRenderer'>)
E                +    where <class 'structlog.processors.JSONRenderer'> = <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'>.JSONRenderer
E                +      where <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'> = structlog.processors

tests/test_logger.py:57: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

stampbot/logger.py:38
  /home/runner/work/stampbot/stampbot/stampbot/logger.py:38: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    elif log_format is not "console":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_auto_kubernetes - AssertionError: assert False
 +  where False = isinstance(<structlog.dev.ConsoleRenderer object at 0x7f2a3dab4910>, <class 'structlog.processors.JSONRenderer'>)
 +    where <class 'structlog.processors.JSONRenderer'> = <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'>.JSONRenderer
 +      where <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'> = structlog.processors
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 91 passed, 3 deselected, 2 warnings in 2.18s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 2, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -37,7 +37,7 @@
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
         return structlog.dev.ConsoleRenderer(colors=True)
-    elif log_format == "auto":
+    elif log_format is not "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
         if is_running_in_kubernetes():
             return structlog.processors.JSONRenderer()
........................................................................ [ 30%]
.....................F
=================================== FAILURES ===================================
_____________________ test_get_log_renderer_unknown_format _____________________

    def test_get_log_renderer_unknown_format():
        """Test fallback to JSON for unknown format."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "unknown_format"
            from stampbot.logger import _get_log_renderer
    
            renderer = _get_log_renderer()
>           assert isinstance(renderer, structlog.processors.JSONRenderer)
E           AssertionError: assert False
E            +  where False = isinstance(<structlog.dev.ConsoleRenderer object at 0x7f6671e52c40>, <class 'structlog.processors.JSONRenderer'>)
E            +    where <class 'structlog.processors.JSONRenderer'> = <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'>.JSONRenderer
E            +      where <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'> = structlog.processors

tests/test_logger.py:78: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

stampbot/logger.py:40
  /home/runner/work/stampbot/stampbot/stampbot/logger.py:40: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    elif log_format is not "auto":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_unknown_format - AssertionError: assert False
 +  where False = isinstance(<structlog.dev.ConsoleRenderer object at 0x7f6671e52c40>, <class 'structlog.processors.JSONRenderer'>)
 +    where <class 'structlog.processors.JSONRenderer'> = <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'>.JSONRenderer
 +      where <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'> = structlog.processors
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 93 passed, 3 deselected, 2 warnings in 2.17s
operator: core/AddNot, occurrence: 0, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -33,7 +33,7 @@
     """
     log_format = settings.log_format.lower()
 
-    if log_format == "json":
+    if not log_format == "json":
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
         return structlog.dev.ConsoleRenderer(colors=True)
........................................................................ [ 30%]
..................F
=================================== FAILURES ===================================
________________________ test_get_log_renderer_console _________________________

    def test_get_log_renderer_console():
        """Test console renderer selection."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "console"
            from stampbot.logger import _get_log_renderer
    
            renderer = _get_log_renderer()
>           assert isinstance(renderer, structlog.dev.ConsoleRenderer)
E           AssertionError: assert False
E            +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f77e94b0a50>, <class 'structlog.dev.ConsoleRenderer'>)
E            +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
E            +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev

tests/test_logger.py:46: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_console - AssertionError: assert False
 +  where False = isinstance(<structlog.processors.JSONRenderer object at 0x7f77e94b0a50>, <class 'structlog.dev.ConsoleRenderer'>)
 +    where <class 'structlog.dev.ConsoleRenderer'> = <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'>.ConsoleRenderer
 +      where <module 'structlog.dev' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/dev.py'> = structlog.dev
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 90 passed, 3 deselected, 1 warning in 2.17s
operator: core/AddNot, occurrence: 1, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -39,7 +39,7 @@
         return structlog.dev.ConsoleRenderer(colors=True)
     elif log_format == "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
-        if is_running_in_kubernetes():
+        if not is_running_in_kubernetes():
             return structlog.processors.JSONRenderer()
         else:
             return structlog.dev.ConsoleRenderer(colors=True)
........................................................................ [ 30%]
...................F
=================================== FAILURES ===================================
____________________ test_get_log_renderer_auto_kubernetes _____________________

    def test_get_log_renderer_auto_kubernetes():
        """Test auto renderer in Kubernetes environment."""
        with patch("stampbot.logger.settings") as mock_settings:
            mock_settings.log_format = "auto"
            with patch("stampbot.logger.is_running_in_kubernetes", return_value=True):
                from stampbot.logger import _get_log_renderer
    
                renderer = _get_log_renderer()
>               assert isinstance(renderer, structlog.processors.JSONRenderer)
E               AssertionError: assert False
E                +  where False = isinstance(<structlog.dev.ConsoleRenderer object at 0x7fec6aab8690>, <class 'structlog.processors.JSONRenderer'>)
E                +    where <class 'structlog.processors.JSONRenderer'> = <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'>.JSONRenderer
E                +      where <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'> = structlog.processors

tests/test_logger.py:57: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_get_log_renderer_auto_kubernetes - AssertionError: assert False
 +  where False = isinstance(<structlog.dev.ConsoleRenderer object at 0x7fec6aab8690>, <class 'structlog.processors.JSONRenderer'>)
 +    where <class 'structlog.processors.JSONRenderer'> = <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'>.JSONRenderer
 +      where <module 'structlog.processors' from '/home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/structlog/processors.py'> = structlog.processors
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 91 passed, 3 deselected, 1 warning in 2.16s
operator: core/AddNot, occurrence: 2, definition_name: configure_logging
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -103,7 +103,7 @@
     root_logger.setLevel(log_level_int)
 
     # Instrument logging with OpenTelemetry if enabled
-    if settings.otel_enabled:
+    if not settings.otel_enabled:
         LoggingInstrumentor().instrument(set_logging_format=True)
 
 
........................................................................ [ 30%]
.......................F
=================================== FAILURES ===================================
___________________ test_configure_logging_with_otel_enabled ___________________

    def test_configure_logging_with_otel_enabled():
        """Test configure_logging instruments logging when OTEL is enabled."""
        with (
            patch("stampbot.logger.settings") as mock_settings,
            patch("stampbot.logger.LoggingInstrumentor") as mock_instrumentor,
        ):
            mock_settings.log_format = "json"
            mock_settings.log_level = "INFO"
            mock_settings.otel_enabled = True
    
            from stampbot.logger import configure_logging
    
            configure_logging()
    
            # Verify LoggingInstrumentor was called
>           mock_instrumentor.return_value.instrument.assert_called_once_with(set_logging_format=True)

tests/test_logger.py:104: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='LoggingInstrumentor().instrument' id='139732552752096'>
args = (), kwargs = {'set_logging_format': True}
msg = "Expected 'instrument' to be called once. Called 0 times."

    def assert_called_once_with(self, /, *args, **kwargs):
        """assert that the mock was called exactly once and that that call was
        with the specified arguments."""
        if not self.call_count == 1:
            msg = ("Expected '%s' to be called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'instrument' to be called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:997: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_configure_logging_with_otel_enabled - AssertionError: Expected 'instrument' to be called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 95 passed, 3 deselected, 1 warning in 2.22s
operator: core/ReplaceTrueWithFalse, occurrence: 0, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -36,7 +36,7 @@
     if log_format == "json":
         return structlog.processors.JSONRenderer()
     elif log_format == "console":
-        return structlog.dev.ConsoleRenderer(colors=True)
+        return structlog.dev.ConsoleRenderer(colors=False)
     elif log_format == "auto":
         # Auto-detect: use JSON in Kubernetes, console otherwise
         if is_running_in_kubernetes():
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceTrueWithFalse, occurrence: 1, definition_name: _get_log_renderer
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -42,7 +42,7 @@
         if is_running_in_kubernetes():
             return structlog.processors.JSONRenderer()
         else:
-            return structlog.dev.ConsoleRenderer(colors=True)
+            return structlog.dev.ConsoleRenderer(colors=False)
     else:
         # Unknown format, default to JSON for safety
         return structlog.processors.JSONRenderer()
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceTrueWithFalse, occurrence: 2, definition_name: configure_logging
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -81,7 +81,7 @@
         context_class=dict,
         # Route structlog through stdlib so all output shares one handler.
         logger_factory=structlog.stdlib.LoggerFactory(),
-        cache_logger_on_first_use=True,
+        cache_logger_on_first_use=False,
     )
 
     # ProcessorFormatter ensures uvicorn access logs and every other stdlib
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceTrueWithFalse, occurrence: 3, definition_name: configure_logging
--- mutation diff ---
--- astampbot/logger.py
+++ bstampbot/logger.py
@@ -104,7 +104,7 @@
 
     # Instrument logging with OpenTelemetry if enabled
     if settings.otel_enabled:
-        LoggingInstrumentor().instrument(set_logging_format=True)
+        LoggingInstrumentor().instrument(set_logging_format=False)
 
 
 def get_logger(name: str) -> structlog.BoundLogger:
........................................................................ [ 30%]
.......................F
=================================== FAILURES ===================================
___________________ test_configure_logging_with_otel_enabled ___________________

    def test_configure_logging_with_otel_enabled():
        """Test configure_logging instruments logging when OTEL is enabled."""
        with (
            patch("stampbot.logger.settings") as mock_settings,
            patch("stampbot.logger.LoggingInstrumentor") as mock_instrumentor,
        ):
            mock_settings.log_format = "json"
            mock_settings.log_level = "INFO"
            mock_settings.otel_enabled = True
    
            from stampbot.logger import configure_logging
    
            configure_logging()
    
            # Verify LoggingInstrumentor was called
>           mock_instrumentor.return_value.instrument.assert_called_once_with(set_logging_format=True)

tests/test_logger.py:104: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:998: in assert_called_once_with
    return self.assert_called_with(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='LoggingInstrumentor().instrument' id='139812664105952'>
args = (), kwargs = {'set_logging_format': True}
expected = call(set_logging_format=True)
actual = call(set_logging_format=False)
_error_message = <function NonCallableMock.assert_called_with.<locals>._error_message at 0x7f28ac29fed0>
cause = None

    def assert_called_with(self, /, *args, **kwargs):
        """assert that the last call was made with the specified arguments.
    
        Raises an AssertionError if the args and keyword args passed in are
        different to the last call to the mock."""
        if self.call_args is None:
            expected = self._format_mock_call_signature(args, kwargs)
            actual = 'not called.'
            error_message = ('expected call not found.\nExpected: %s\n  Actual: %s'
                    % (expected, actual))
            raise AssertionError(error_message)
    
        def _error_message():
            msg = self._format_mock_failure_message(args, kwargs)
            return msg
        expected = self._call_matcher(_Call((args, kwargs), two=True))
        actual = self._call_matcher(self.call_args)
        if actual != expected:
            cause = expected if isinstance(expected, Exception) else None
>           raise AssertionError(_error_message()) from cause
E           AssertionError: expected call not found.
E           Expected: instrument(set_logging_format=True)
E             Actual: instrument(set_logging_format=False)

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:986: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_logger.py::test_configure_logging_with_otel_enabled - AssertionError: expected call not found.
Expected: instrument(set_logging_format=True)
  Actual: instrument(set_logging_format=False)
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 95 passed, 3 deselected, 1 warning in 2.26s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -31,7 +31,7 @@
         raise ValueError(f"Invalid {name}: must be a complete URL")
 
     # Allow http only for localhost (development)
-    if parsed.scheme == "http":
+    if parsed.scheme != "http":
         if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
     elif parsed.scheme != "https":
........................................................................ [ 30%]
..................................................F
=================================== FAILURES ===================================
_________________ TestUrlValidation.test_allows_http_localhost _________________

self = <tests.test_manifest.TestUrlValidation object at 0x7fc8ea642d50>

    def test_allows_http_localhost(self):
        """Test that HTTP URLs for localhost are allowed."""
>       manifest = create_manifest(
            redirect_url="http://localhost:8000/setup/callback",
            webhook_url="http://localhost:8000/webhook",
        )

tests/test_manifest.py:32: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/manifest.py:85: in create_manifest
    _validate_url(redirect_url, "redirect_url")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = 'http://localhost:8000/setup/callback', name = 'redirect_url'

    def _validate_url(url: str, name: str) -> None:
        """Validate that a URL is well-formed and uses HTTPS (or localhost).
    
        Args:
            url: URL to validate
            name: Name of the URL parameter for error messages
    
        Raises:
            ValueError: If URL is invalid or doesn't use HTTPS
        """
        parsed = urlparse(url)
    
        if not parsed.scheme or not parsed.netloc:
            raise ValueError(f"Invalid {name}: must be a complete URL")
    
        # Allow http only for localhost (development)
        if parsed.scheme != "http":
            if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
                raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
        elif parsed.scheme != "https":
>           raise ValueError(f"Invalid {name}: must use HTTPS")
E           ValueError: Invalid redirect_url: must use HTTPS

stampbot/manifest.py:38: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestUrlValidation::test_allows_http_localhost - ValueError: Invalid redirect_url: must use HTTPS
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 122 passed, 3 deselected, 1 warning in 2.40s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -31,7 +31,7 @@
         raise ValueError(f"Invalid {name}: must be a complete URL")
 
     # Allow http only for localhost (development)
-    if parsed.scheme == "http":
+    if parsed.scheme < "http":
         if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
     elif parsed.scheme != "https":
........................................................................ [ 30%]
..................................................F
=================================== FAILURES ===================================
_________________ TestUrlValidation.test_allows_http_localhost _________________

self = <tests.test_manifest.TestUrlValidation object at 0x7fc02f67ed50>

    def test_allows_http_localhost(self):
        """Test that HTTP URLs for localhost are allowed."""
>       manifest = create_manifest(
            redirect_url="http://localhost:8000/setup/callback",
            webhook_url="http://localhost:8000/webhook",
        )

tests/test_manifest.py:32: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/manifest.py:85: in create_manifest
    _validate_url(redirect_url, "redirect_url")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = 'http://localhost:8000/setup/callback', name = 'redirect_url'

    def _validate_url(url: str, name: str) -> None:
        """Validate that a URL is well-formed and uses HTTPS (or localhost).
    
        Args:
            url: URL to validate
            name: Name of the URL parameter for error messages
    
        Raises:
            ValueError: If URL is invalid or doesn't use HTTPS
        """
        parsed = urlparse(url)
    
        if not parsed.scheme or not parsed.netloc:
            raise ValueError(f"Invalid {name}: must be a complete URL")
    
        # Allow http only for localhost (development)
        if parsed.scheme < "http":
            if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
                raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
        elif parsed.scheme != "https":
>           raise ValueError(f"Invalid {name}: must use HTTPS")
E           ValueError: Invalid redirect_url: must use HTTPS

stampbot/manifest.py:38: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestUrlValidation::test_allows_http_localhost - ValueError: Invalid redirect_url: must use HTTPS
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 122 passed, 3 deselected, 1 warning in 2.40s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -31,7 +31,7 @@
         raise ValueError(f"Invalid {name}: must be a complete URL")
 
     # Allow http only for localhost (development)
-    if parsed.scheme == "http":
+    if parsed.scheme <= "http":
         if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
     elif parsed.scheme != "https":
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -31,7 +31,7 @@
         raise ValueError(f"Invalid {name}: must be a complete URL")
 
     # Allow http only for localhost (development)
-    if parsed.scheme == "http":
+    if parsed.scheme > "http":
         if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
     elif parsed.scheme != "https":
........................................................................ [ 30%]
..................................................F
=================================== FAILURES ===================================
_________________ TestUrlValidation.test_allows_http_localhost _________________

self = <tests.test_manifest.TestUrlValidation object at 0x7fe4c1e9ed50>

    def test_allows_http_localhost(self):
        """Test that HTTP URLs for localhost are allowed."""
>       manifest = create_manifest(
            redirect_url="http://localhost:8000/setup/callback",
            webhook_url="http://localhost:8000/webhook",
        )

tests/test_manifest.py:32: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/manifest.py:85: in create_manifest
    _validate_url(redirect_url, "redirect_url")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = 'http://localhost:8000/setup/callback', name = 'redirect_url'

    def _validate_url(url: str, name: str) -> None:
        """Validate that a URL is well-formed and uses HTTPS (or localhost).
    
        Args:
            url: URL to validate
            name: Name of the URL parameter for error messages
    
        Raises:
            ValueError: If URL is invalid or doesn't use HTTPS
        """
        parsed = urlparse(url)
    
        if not parsed.scheme or not parsed.netloc:
            raise ValueError(f"Invalid {name}: must be a complete URL")
    
        # Allow http only for localhost (development)
        if parsed.scheme > "http":
            if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
                raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
        elif parsed.scheme != "https":
>           raise ValueError(f"Invalid {name}: must use HTTPS")
E           ValueError: Invalid redirect_url: must use HTTPS

stampbot/manifest.py:38: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestUrlValidation::test_allows_http_localhost - ValueError: Invalid redirect_url: must use HTTPS
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 122 passed, 3 deselected, 1 warning in 2.39s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -31,7 +31,7 @@
         raise ValueError(f"Invalid {name}: must be a complete URL")
 
     # Allow http only for localhost (development)
-    if parsed.scheme == "http":
+    if parsed.scheme >= "http":
         if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
     elif parsed.scheme != "https":
........................................................................ [ 30%]
.....................................................F
=================================== FAILURES ===================================
________ TestCreateManifest.test_manifest_contains_required_permissions ________

self = <tests.test_manifest.TestCreateManifest object at 0x7f97242b3110>

    def test_manifest_contains_required_permissions(self):
        """Test manifest contains required permissions."""
>       manifest = create_manifest(
            redirect_url="https://example.com/setup/callback",
        )

tests/test_manifest.py:63: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/manifest.py:85: in create_manifest
    _validate_url(redirect_url, "redirect_url")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = 'https://example.com/setup/callback', name = 'redirect_url'

    def _validate_url(url: str, name: str) -> None:
        """Validate that a URL is well-formed and uses HTTPS (or localhost).
    
        Args:
            url: URL to validate
            name: Name of the URL parameter for error messages
    
        Raises:
            ValueError: If URL is invalid or doesn't use HTTPS
        """
        parsed = urlparse(url)
    
        if not parsed.scheme or not parsed.netloc:
            raise ValueError(f"Invalid {name}: must be a complete URL")
    
        # Allow http only for localhost (development)
        if parsed.scheme >= "http":
            if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
>               raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
E               ValueError: Invalid redirect_url: must use HTTPS (HTTP only allowed for localhost)

stampbot/manifest.py:36: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestCreateManifest::test_manifest_contains_required_permissions - ValueError: Invalid redirect_url: must use HTTPS (HTTP only allowed for localhost)
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 125 passed, 3 deselected, 1 warning in 2.40s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -31,7 +31,7 @@
         raise ValueError(f"Invalid {name}: must be a complete URL")
 
     # Allow http only for localhost (development)
-    if parsed.scheme == "http":
+    if parsed.scheme is "http":
         if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
     elif parsed.scheme != "https":
........................................................................ [ 30%]
..................................................F
=================================== FAILURES ===================================
_________________ TestUrlValidation.test_allows_http_localhost _________________

self = <tests.test_manifest.TestUrlValidation object at 0x7f3e13872e90>

    def test_allows_http_localhost(self):
        """Test that HTTP URLs for localhost are allowed."""
>       manifest = create_manifest(
            redirect_url="http://localhost:8000/setup/callback",
            webhook_url="http://localhost:8000/webhook",
        )

tests/test_manifest.py:32: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/manifest.py:85: in create_manifest
    _validate_url(redirect_url, "redirect_url")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = 'http://localhost:8000/setup/callback', name = 'redirect_url'

    def _validate_url(url: str, name: str) -> None:
        """Validate that a URL is well-formed and uses HTTPS (or localhost).
    
        Args:
            url: URL to validate
            name: Name of the URL parameter for error messages
    
        Raises:
            ValueError: If URL is invalid or doesn't use HTTPS
        """
        parsed = urlparse(url)
    
        if not parsed.scheme or not parsed.netloc:
            raise ValueError(f"Invalid {name}: must be a complete URL")
    
        # Allow http only for localhost (development)
        if parsed.scheme is "http":
            if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
                raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
        elif parsed.scheme != "https":
>           raise ValueError(f"Invalid {name}: must use HTTPS")
E           ValueError: Invalid redirect_url: must use HTTPS

stampbot/manifest.py:38: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

stampbot/manifest.py:34
  /home/runner/work/stampbot/stampbot/stampbot/manifest.py:34: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    if parsed.scheme is "http":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestUrlValidation::test_allows_http_localhost - ValueError: Invalid redirect_url: must use HTTPS
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 122 passed, 3 deselected, 2 warnings in 2.39s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -31,7 +31,7 @@
         raise ValueError(f"Invalid {name}: must be a complete URL")
 
     # Allow http only for localhost (development)
-    if parsed.scheme == "http":
+    if parsed.scheme is not "http":
         if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
     elif parsed.scheme != "https":
........................................................................ [ 30%]
.....................................................F
=================================== FAILURES ===================================
________ TestCreateManifest.test_manifest_contains_required_permissions ________

self = <tests.test_manifest.TestCreateManifest object at 0x7f302c0c7250>

    def test_manifest_contains_required_permissions(self):
        """Test manifest contains required permissions."""
>       manifest = create_manifest(
            redirect_url="https://example.com/setup/callback",
        )

tests/test_manifest.py:63: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/manifest.py:85: in create_manifest
    _validate_url(redirect_url, "redirect_url")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = 'https://example.com/setup/callback', name = 'redirect_url'

    def _validate_url(url: str, name: str) -> None:
        """Validate that a URL is well-formed and uses HTTPS (or localhost).
    
        Args:
            url: URL to validate
            name: Name of the URL parameter for error messages
    
        Raises:
            ValueError: If URL is invalid or doesn't use HTTPS
        """
        parsed = urlparse(url)
    
        if not parsed.scheme or not parsed.netloc:
            raise ValueError(f"Invalid {name}: must be a complete URL")
    
        # Allow http only for localhost (development)
        if parsed.scheme is not "http":
            if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
>               raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
E               ValueError: Invalid redirect_url: must use HTTPS (HTTP only allowed for localhost)

stampbot/manifest.py:36: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

stampbot/manifest.py:34
  /home/runner/work/stampbot/stampbot/stampbot/manifest.py:34: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    if parsed.scheme is not "http":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestCreateManifest::test_manifest_contains_required_permissions - ValueError: Invalid redirect_url: must use HTTPS (HTTP only allowed for localhost)
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 125 passed, 3 deselected, 2 warnings in 2.40s
operator: core/ReplaceComparisonOperator_NotEq_Eq, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -34,7 +34,7 @@
     if parsed.scheme == "http":
         if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
-    elif parsed.scheme != "https":
+    elif parsed.scheme == "https":
         raise ValueError(f"Invalid {name}: must use HTTPS")
 
 
........................................................................ [ 30%]
.....................................................F
=================================== FAILURES ===================================
________ TestCreateManifest.test_manifest_contains_required_permissions ________

self = <tests.test_manifest.TestCreateManifest object at 0x7f5541d9f110>

    def test_manifest_contains_required_permissions(self):
        """Test manifest contains required permissions."""
>       manifest = create_manifest(
            redirect_url="https://example.com/setup/callback",
        )

tests/test_manifest.py:63: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/manifest.py:85: in create_manifest
    _validate_url(redirect_url, "redirect_url")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = 'https://example.com/setup/callback', name = 'redirect_url'

    def _validate_url(url: str, name: str) -> None:
        """Validate that a URL is well-formed and uses HTTPS (or localhost).
    
        Args:
            url: URL to validate
            name: Name of the URL parameter for error messages
    
        Raises:
            ValueError: If URL is invalid or doesn't use HTTPS
        """
        parsed = urlparse(url)
    
        if not parsed.scheme or not parsed.netloc:
            raise ValueError(f"Invalid {name}: must be a complete URL")
    
        # Allow http only for localhost (development)
        if parsed.scheme == "http":
            if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
                raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
        elif parsed.scheme == "https":
>           raise ValueError(f"Invalid {name}: must use HTTPS")
E           ValueError: Invalid redirect_url: must use HTTPS

stampbot/manifest.py:38: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestCreateManifest::test_manifest_contains_required_permissions - ValueError: Invalid redirect_url: must use HTTPS
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 125 passed, 3 deselected, 1 warning in 2.43s
operator: core/ReplaceComparisonOperator_NotEq_Lt, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -34,7 +34,7 @@
     if parsed.scheme == "http":
         if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
-    elif parsed.scheme != "https":
+    elif parsed.scheme < "https":
         raise ValueError(f"Invalid {name}: must use HTTPS")
 
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_NotEq_LtE, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -34,7 +34,7 @@
     if parsed.scheme == "http":
         if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
-    elif parsed.scheme != "https":
+    elif parsed.scheme <= "https":
         raise ValueError(f"Invalid {name}: must use HTTPS")
 
 
........................................................................ [ 30%]
.....................................................F
=================================== FAILURES ===================================
________ TestCreateManifest.test_manifest_contains_required_permissions ________

self = <tests.test_manifest.TestCreateManifest object at 0x7fe484e8b110>

    def test_manifest_contains_required_permissions(self):
        """Test manifest contains required permissions."""
>       manifest = create_manifest(
            redirect_url="https://example.com/setup/callback",
        )

tests/test_manifest.py:63: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/manifest.py:85: in create_manifest
    _validate_url(redirect_url, "redirect_url")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = 'https://example.com/setup/callback', name = 'redirect_url'

    def _validate_url(url: str, name: str) -> None:
        """Validate that a URL is well-formed and uses HTTPS (or localhost).
    
        Args:
            url: URL to validate
            name: Name of the URL parameter for error messages
    
        Raises:
            ValueError: If URL is invalid or doesn't use HTTPS
        """
        parsed = urlparse(url)
    
        if not parsed.scheme or not parsed.netloc:
            raise ValueError(f"Invalid {name}: must be a complete URL")
    
        # Allow http only for localhost (development)
        if parsed.scheme == "http":
            if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
                raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
        elif parsed.scheme <= "https":
>           raise ValueError(f"Invalid {name}: must use HTTPS")
E           ValueError: Invalid redirect_url: must use HTTPS

stampbot/manifest.py:38: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestCreateManifest::test_manifest_contains_required_permissions - ValueError: Invalid redirect_url: must use HTTPS
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 125 passed, 3 deselected, 1 warning in 2.57s
operator: core/ReplaceComparisonOperator_NotEq_Gt, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -34,7 +34,7 @@
     if parsed.scheme == "http":
         if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
-    elif parsed.scheme != "https":
+    elif parsed.scheme > "https":
         raise ValueError(f"Invalid {name}: must use HTTPS")
 
 
........................................................................ [ 30%]
....................................................F
=================================== FAILURES ===================================
_______________ TestUrlValidation.test_rejects_non_https_scheme ________________

self = <tests.test_manifest.TestUrlValidation object at 0x7fca008af820>

    def test_rejects_non_https_scheme(self):
        """Test that non-HTTPS schemes are rejected for webhook URLs."""
        import pytest
    
>       with pytest.raises(ValueError, match="must use HTTPS"):
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       Failed: DID NOT RAISE <class 'ValueError'>

tests/test_manifest.py:51: Failed
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestUrlValidation::test_rejects_non_https_scheme - Failed: DID NOT RAISE <class 'ValueError'>
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 124 passed, 3 deselected, 1 warning in 2.40s
operator: core/ReplaceComparisonOperator_NotEq_GtE, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -34,7 +34,7 @@
     if parsed.scheme == "http":
         if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
-    elif parsed.scheme != "https":
+    elif parsed.scheme >= "https":
         raise ValueError(f"Invalid {name}: must use HTTPS")
 
 
........................................................................ [ 30%]
.....................................................F
=================================== FAILURES ===================================
________ TestCreateManifest.test_manifest_contains_required_permissions ________

self = <tests.test_manifest.TestCreateManifest object at 0x7fbb27bbf110>

    def test_manifest_contains_required_permissions(self):
        """Test manifest contains required permissions."""
>       manifest = create_manifest(
            redirect_url="https://example.com/setup/callback",
        )

tests/test_manifest.py:63: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/manifest.py:85: in create_manifest
    _validate_url(redirect_url, "redirect_url")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = 'https://example.com/setup/callback', name = 'redirect_url'

    def _validate_url(url: str, name: str) -> None:
        """Validate that a URL is well-formed and uses HTTPS (or localhost).
    
        Args:
            url: URL to validate
            name: Name of the URL parameter for error messages
    
        Raises:
            ValueError: If URL is invalid or doesn't use HTTPS
        """
        parsed = urlparse(url)
    
        if not parsed.scheme or not parsed.netloc:
            raise ValueError(f"Invalid {name}: must be a complete URL")
    
        # Allow http only for localhost (development)
        if parsed.scheme == "http":
            if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
                raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
        elif parsed.scheme >= "https":
>           raise ValueError(f"Invalid {name}: must use HTTPS")
E           ValueError: Invalid redirect_url: must use HTTPS

stampbot/manifest.py:38: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestCreateManifest::test_manifest_contains_required_permissions - ValueError: Invalid redirect_url: must use HTTPS
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 125 passed, 3 deselected, 1 warning in 2.40s
operator: core/ReplaceComparisonOperator_NotEq_Is, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -34,7 +34,7 @@
     if parsed.scheme == "http":
         if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
-    elif parsed.scheme != "https":
+    elif parsed.scheme is "https":
         raise ValueError(f"Invalid {name}: must use HTTPS")
 
 
........................................................................ [ 30%]
....................................................F
=================================== FAILURES ===================================
_______________ TestUrlValidation.test_rejects_non_https_scheme ________________

self = <tests.test_manifest.TestUrlValidation object at 0x7ff73c8df820>

    def test_rejects_non_https_scheme(self):
        """Test that non-HTTPS schemes are rejected for webhook URLs."""
        import pytest
    
>       with pytest.raises(ValueError, match="must use HTTPS"):
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       Failed: DID NOT RAISE <class 'ValueError'>

tests/test_manifest.py:51: Failed
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

stampbot/manifest.py:37
  /home/runner/work/stampbot/stampbot/stampbot/manifest.py:37: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    elif parsed.scheme is "https":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestUrlValidation::test_rejects_non_https_scheme - Failed: DID NOT RAISE <class 'ValueError'>
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 124 passed, 3 deselected, 2 warnings in 2.41s
operator: core/ReplaceComparisonOperator_NotEq_IsNot, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -34,7 +34,7 @@
     if parsed.scheme == "http":
         if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
-    elif parsed.scheme != "https":
+    elif parsed.scheme is not "https":
         raise ValueError(f"Invalid {name}: must use HTTPS")
 
 
........................................................................ [ 30%]
.....................................................F
=================================== FAILURES ===================================
________ TestCreateManifest.test_manifest_contains_required_permissions ________

self = <tests.test_manifest.TestCreateManifest object at 0x7fe844cbf250>

    def test_manifest_contains_required_permissions(self):
        """Test manifest contains required permissions."""
>       manifest = create_manifest(
            redirect_url="https://example.com/setup/callback",
        )

tests/test_manifest.py:63: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/manifest.py:85: in create_manifest
    _validate_url(redirect_url, "redirect_url")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = 'https://example.com/setup/callback', name = 'redirect_url'

    def _validate_url(url: str, name: str) -> None:
        """Validate that a URL is well-formed and uses HTTPS (or localhost).
    
        Args:
            url: URL to validate
            name: Name of the URL parameter for error messages
    
        Raises:
            ValueError: If URL is invalid or doesn't use HTTPS
        """
        parsed = urlparse(url)
    
        if not parsed.scheme or not parsed.netloc:
            raise ValueError(f"Invalid {name}: must be a complete URL")
    
        # Allow http only for localhost (development)
        if parsed.scheme == "http":
            if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
                raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
        elif parsed.scheme is not "https":
>           raise ValueError(f"Invalid {name}: must use HTTPS")
E           ValueError: Invalid redirect_url: must use HTTPS

stampbot/manifest.py:38: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

stampbot/manifest.py:37
  /home/runner/work/stampbot/stampbot/stampbot/manifest.py:37: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    elif parsed.scheme is not "https":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestCreateManifest::test_manifest_contains_required_permissions - ValueError: Invalid redirect_url: must use HTTPS
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 125 passed, 3 deselected, 2 warnings in 2.40s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -27,7 +27,7 @@
     """
     parsed = urlparse(url)
 
-    if not parsed.scheme or not parsed.netloc:
+    if  parsed.scheme or not parsed.netloc:
         raise ValueError(f"Invalid {name}: must be a complete URL")
 
     # Allow http only for localhost (development)
........................................................................ [ 30%]
.................................................F
=================================== FAILURES ===================================
__________ TestUrlValidation.test_rejects_http_non_localhost_redirect __________

self = <tests.test_manifest.TestUrlValidation object at 0x7f7f6e7a6e90>

    def test_rejects_http_non_localhost_redirect(self):
        """Test that HTTP redirect URLs for non-localhost are rejected."""
        import pytest
    
        with pytest.raises(ValueError, match="must use HTTPS"):
>           create_manifest(
                redirect_url="http://example.com/setup/callback",
            )

tests/test_manifest.py:26: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/manifest.py:85: in create_manifest
    _validate_url(redirect_url, "redirect_url")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = 'http://example.com/setup/callback', name = 'redirect_url'

    def _validate_url(url: str, name: str) -> None:
        """Validate that a URL is well-formed and uses HTTPS (or localhost).
    
        Args:
            url: URL to validate
            name: Name of the URL parameter for error messages
    
        Raises:
            ValueError: If URL is invalid or doesn't use HTTPS
        """
        parsed = urlparse(url)
    
        if  parsed.scheme or not parsed.netloc:
>           raise ValueError(f"Invalid {name}: must be a complete URL")
E           ValueError: Invalid redirect_url: must be a complete URL

stampbot/manifest.py:31: ValueError

During handling of the above exception, another exception occurred:

self = <tests.test_manifest.TestUrlValidation object at 0x7f7f6e7a6e90>

    def test_rejects_http_non_localhost_redirect(self):
        """Test that HTTP redirect URLs for non-localhost are rejected."""
        import pytest
    
>       with pytest.raises(ValueError, match="must use HTTPS"):
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       AssertionError: Regex pattern did not match.
E         Expected regex: 'must use HTTPS'
E         Actual message: 'Invalid redirect_url: must be a complete URL'

tests/test_manifest.py:25: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestUrlValidation::test_rejects_http_non_localhost_redirect - AssertionError: Regex pattern did not match.
  Expected regex: 'must use HTTPS'
  Actual message: 'Invalid redirect_url: must be a complete URL'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 121 passed, 3 deselected, 1 warning in 2.41s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 1, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -27,7 +27,7 @@
     """
     parsed = urlparse(url)
 
-    if not parsed.scheme or not parsed.netloc:
+    if not parsed.scheme or  parsed.netloc:
         raise ValueError(f"Invalid {name}: must be a complete URL")
 
     # Allow http only for localhost (development)
........................................................................ [ 30%]
.................................................F
=================================== FAILURES ===================================
__________ TestUrlValidation.test_rejects_http_non_localhost_redirect __________

self = <tests.test_manifest.TestUrlValidation object at 0x7f75414d2e90>

    def test_rejects_http_non_localhost_redirect(self):
        """Test that HTTP redirect URLs for non-localhost are rejected."""
        import pytest
    
        with pytest.raises(ValueError, match="must use HTTPS"):
>           create_manifest(
                redirect_url="http://example.com/setup/callback",
            )

tests/test_manifest.py:26: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/manifest.py:85: in create_manifest
    _validate_url(redirect_url, "redirect_url")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = 'http://example.com/setup/callback', name = 'redirect_url'

    def _validate_url(url: str, name: str) -> None:
        """Validate that a URL is well-formed and uses HTTPS (or localhost).
    
        Args:
            url: URL to validate
            name: Name of the URL parameter for error messages
    
        Raises:
            ValueError: If URL is invalid or doesn't use HTTPS
        """
        parsed = urlparse(url)
    
        if not parsed.scheme or  parsed.netloc:
>           raise ValueError(f"Invalid {name}: must be a complete URL")
E           ValueError: Invalid redirect_url: must be a complete URL

stampbot/manifest.py:31: ValueError

During handling of the above exception, another exception occurred:

self = <tests.test_manifest.TestUrlValidation object at 0x7f75414d2e90>

    def test_rejects_http_non_localhost_redirect(self):
        """Test that HTTP redirect URLs for non-localhost are rejected."""
        import pytest
    
>       with pytest.raises(ValueError, match="must use HTTPS"):
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       AssertionError: Regex pattern did not match.
E         Expected regex: 'must use HTTPS'
E         Actual message: 'Invalid redirect_url: must be a complete URL'

tests/test_manifest.py:25: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestUrlValidation::test_rejects_http_non_localhost_redirect - AssertionError: Regex pattern did not match.
  Expected regex: 'must use HTTPS'
  Actual message: 'Invalid redirect_url: must be a complete URL'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 121 passed, 3 deselected, 1 warning in 2.40s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 2, definition_name: exchange_code_for_credentials
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -147,7 +147,7 @@
         ValueError: If code contains invalid characters
     """
     # Validate code to prevent SSRF - GitHub codes are alphanumeric
-    if not code or not code.isalnum():
+    if  code or not code.isalnum():
         raise ValueError("Invalid manifest code format")
 
     url = GITHUB_MANIFEST_CONVERSION_URL.format(code=code)
........................................................................ [ 30%]
................................................................F
=================================== FAILURES ===================================
_________________ TestExchangeCode.test_exchange_code_success __________________

self = <tests.test_manifest.TestExchangeCode object at 0x7fc0ea8ab610>

    @pytest.mark.asyncio
    async def test_exchange_code_success(self):
        """Test successful code exchange."""
        import httpx
    
        mock_response_data = {
            "id": 12345,
            "pem": "-----BEGIN RSA PRIVATE KEY-----\ntest\n-----END RSA PRIVATE KEY-----",
            "webhook_secret": "test-secret",
            "slug": "my-stampbot",
            "name": "My Stampbot",
            "client_id": "client123",
            "client_secret": "secret456",
        }
    
        # Create a proper mock response with request attached
        mock_request = httpx.Request(
            "POST", "https://api.github.com/app-manifests/testcode123/conversions"
        )
        mock_response = httpx.Response(200, json=mock_response_data, request=mock_request)
    
        with patch("httpx.AsyncClient.post", new_callable=AsyncMock) as mock_post:
            mock_post.return_value = mock_response
    
>           result = await exchange_code_for_credentials("testcode123")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_manifest.py:206: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

code = 'testcode123'

    async def exchange_code_for_credentials(code: str) -> dict[str, Any]:
        """Exchange the temporary code for app credentials.
    
        After a user creates a GitHub App from a manifest, GitHub redirects
        to the callback URL with a temporary code. This function exchanges
        that code for the actual app credentials.
    
        Args:
            code: Temporary code from GitHub callback
    
        Returns:
            Dictionary with app credentials:
            - id: App ID
            - pem: Private key (PEM format)
            - webhook_secret: Webhook secret
            - slug: App slug
            - name: App name
            - client_id: OAuth client ID
            - client_secret: OAuth client secret
    
        Raises:
            httpx.HTTPStatusError: If API call fails
            ValueError: If code contains invalid characters
        """
        # Validate code to prevent SSRF - GitHub codes are alphanumeric
        if  code or not code.isalnum():
>           raise ValueError("Invalid manifest code format")
E           ValueError: Invalid manifest code format

stampbot/manifest.py:151: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestExchangeCode::test_exchange_code_success - ValueError: Invalid manifest code format
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 136 passed, 3 deselected, 1 warning in 2.40s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 3, definition_name: exchange_code_for_credentials
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -147,7 +147,7 @@
         ValueError: If code contains invalid characters
     """
     # Validate code to prevent SSRF - GitHub codes are alphanumeric
-    if not code or not code.isalnum():
+    if not code or  code.isalnum():
         raise ValueError("Invalid manifest code format")
 
     url = GITHUB_MANIFEST_CONVERSION_URL.format(code=code)
........................................................................ [ 30%]
................................................................F
=================================== FAILURES ===================================
_________________ TestExchangeCode.test_exchange_code_success __________________

self = <tests.test_manifest.TestExchangeCode object at 0x7fe4c53cb610>

    @pytest.mark.asyncio
    async def test_exchange_code_success(self):
        """Test successful code exchange."""
        import httpx
    
        mock_response_data = {
            "id": 12345,
            "pem": "-----BEGIN RSA PRIVATE KEY-----\ntest\n-----END RSA PRIVATE KEY-----",
            "webhook_secret": "test-secret",
            "slug": "my-stampbot",
            "name": "My Stampbot",
            "client_id": "client123",
            "client_secret": "secret456",
        }
    
        # Create a proper mock response with request attached
        mock_request = httpx.Request(
            "POST", "https://api.github.com/app-manifests/testcode123/conversions"
        )
        mock_response = httpx.Response(200, json=mock_response_data, request=mock_request)
    
        with patch("httpx.AsyncClient.post", new_callable=AsyncMock) as mock_post:
            mock_post.return_value = mock_response
    
>           result = await exchange_code_for_credentials("testcode123")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_manifest.py:206: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

code = 'testcode123'

    async def exchange_code_for_credentials(code: str) -> dict[str, Any]:
        """Exchange the temporary code for app credentials.
    
        After a user creates a GitHub App from a manifest, GitHub redirects
        to the callback URL with a temporary code. This function exchanges
        that code for the actual app credentials.
    
        Args:
            code: Temporary code from GitHub callback
    
        Returns:
            Dictionary with app credentials:
            - id: App ID
            - pem: Private key (PEM format)
            - webhook_secret: Webhook secret
            - slug: App slug
            - name: App name
            - client_id: OAuth client ID
            - client_secret: OAuth client secret
    
        Raises:
            httpx.HTTPStatusError: If API call fails
            ValueError: If code contains invalid characters
        """
        # Validate code to prevent SSRF - GitHub codes are alphanumeric
        if not code or  code.isalnum():
>           raise ValueError("Invalid manifest code format")
E           ValueError: Invalid manifest code format

stampbot/manifest.py:151: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestExchangeCode::test_exchange_code_success - ValueError: Invalid manifest code format
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 136 passed, 3 deselected, 1 warning in 2.39s
operator: core/AddNot, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -27,7 +27,7 @@
     """
     parsed = urlparse(url)
 
-    if not parsed.scheme or not parsed.netloc:
+    if not not parsed.scheme or not parsed.netloc:
         raise ValueError(f"Invalid {name}: must be a complete URL")
 
     # Allow http only for localhost (development)
........................................................................ [ 30%]
.................................................F
=================================== FAILURES ===================================
__________ TestUrlValidation.test_rejects_http_non_localhost_redirect __________

self = <tests.test_manifest.TestUrlValidation object at 0x7f2f9ac9ae90>

    def test_rejects_http_non_localhost_redirect(self):
        """Test that HTTP redirect URLs for non-localhost are rejected."""
        import pytest
    
        with pytest.raises(ValueError, match="must use HTTPS"):
>           create_manifest(
                redirect_url="http://example.com/setup/callback",
            )

tests/test_manifest.py:26: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/manifest.py:85: in create_manifest
    _validate_url(redirect_url, "redirect_url")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = 'http://example.com/setup/callback', name = 'redirect_url'

    def _validate_url(url: str, name: str) -> None:
        """Validate that a URL is well-formed and uses HTTPS (or localhost).
    
        Args:
            url: URL to validate
            name: Name of the URL parameter for error messages
    
        Raises:
            ValueError: If URL is invalid or doesn't use HTTPS
        """
        parsed = urlparse(url)
    
        if not not parsed.scheme or not parsed.netloc:
>           raise ValueError(f"Invalid {name}: must be a complete URL")
E           ValueError: Invalid redirect_url: must be a complete URL

stampbot/manifest.py:31: ValueError

During handling of the above exception, another exception occurred:

self = <tests.test_manifest.TestUrlValidation object at 0x7f2f9ac9ae90>

    def test_rejects_http_non_localhost_redirect(self):
        """Test that HTTP redirect URLs for non-localhost are rejected."""
        import pytest
    
>       with pytest.raises(ValueError, match="must use HTTPS"):
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       AssertionError: Regex pattern did not match.
E         Expected regex: 'must use HTTPS'
E         Actual message: 'Invalid redirect_url: must be a complete URL'

tests/test_manifest.py:25: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestUrlValidation::test_rejects_http_non_localhost_redirect - AssertionError: Regex pattern did not match.
  Expected regex: 'must use HTTPS'
  Actual message: 'Invalid redirect_url: must be a complete URL'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 121 passed, 3 deselected, 1 warning in 2.40s
operator: core/AddNot, occurrence: 1, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -31,7 +31,7 @@
         raise ValueError(f"Invalid {name}: must be a complete URL")
 
     # Allow http only for localhost (development)
-    if parsed.scheme == "http":
+    if not parsed.scheme == "http":
         if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
     elif parsed.scheme != "https":
........................................................................ [ 30%]
..................................................F
=================================== FAILURES ===================================
_________________ TestUrlValidation.test_allows_http_localhost _________________

self = <tests.test_manifest.TestUrlValidation object at 0x7fce2a696d50>

    def test_allows_http_localhost(self):
        """Test that HTTP URLs for localhost are allowed."""
>       manifest = create_manifest(
            redirect_url="http://localhost:8000/setup/callback",
            webhook_url="http://localhost:8000/webhook",
        )

tests/test_manifest.py:32: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/manifest.py:85: in create_manifest
    _validate_url(redirect_url, "redirect_url")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = 'http://localhost:8000/setup/callback', name = 'redirect_url'

    def _validate_url(url: str, name: str) -> None:
        """Validate that a URL is well-formed and uses HTTPS (or localhost).
    
        Args:
            url: URL to validate
            name: Name of the URL parameter for error messages
    
        Raises:
            ValueError: If URL is invalid or doesn't use HTTPS
        """
        parsed = urlparse(url)
    
        if not parsed.scheme or not parsed.netloc:
            raise ValueError(f"Invalid {name}: must be a complete URL")
    
        # Allow http only for localhost (development)
        if not parsed.scheme == "http":
            if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
                raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
        elif parsed.scheme != "https":
>           raise ValueError(f"Invalid {name}: must use HTTPS")
E           ValueError: Invalid redirect_url: must use HTTPS

stampbot/manifest.py:38: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestUrlValidation::test_allows_http_localhost - ValueError: Invalid redirect_url: must use HTTPS
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 122 passed, 3 deselected, 1 warning in 2.42s
operator: core/AddNot, occurrence: 2, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -32,7 +32,7 @@
 
     # Allow http only for localhost (development)
     if parsed.scheme == "http":
-        if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
+        if not parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
             raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
     elif parsed.scheme != "https":
         raise ValueError(f"Invalid {name}: must use HTTPS")
........................................................................ [ 30%]
.................................................F
=================================== FAILURES ===================================
__________ TestUrlValidation.test_rejects_http_non_localhost_redirect __________

self = <tests.test_manifest.TestUrlValidation object at 0x7ff61cbbee90>

    def test_rejects_http_non_localhost_redirect(self):
        """Test that HTTP redirect URLs for non-localhost are rejected."""
        import pytest
    
>       with pytest.raises(ValueError, match="must use HTTPS"):
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       Failed: DID NOT RAISE <class 'ValueError'>

tests/test_manifest.py:25: Failed
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestUrlValidation::test_rejects_http_non_localhost_redirect - Failed: DID NOT RAISE <class 'ValueError'>
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 121 passed, 3 deselected, 1 warning in 2.38s
operator: core/AddNot, occurrence: 3, definition_name: create_manifest
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -98,7 +98,7 @@
     }
 
     # Only include webhook URL if provided; GitHub will prompt for it otherwise
-    if webhook_url:
+    if not webhook_url:
         _validate_url(webhook_url, "webhook_url")
         manifest["hook_attributes"] = {
             "url": webhook_url,
........................................................................ [ 30%]
..................................................F
=================================== FAILURES ===================================
_________________ TestUrlValidation.test_allows_http_localhost _________________

self = <tests.test_manifest.TestUrlValidation object at 0x7f944ae76d50>

    def test_allows_http_localhost(self):
        """Test that HTTP URLs for localhost are allowed."""
        manifest = create_manifest(
            redirect_url="http://localhost:8000/setup/callback",
            webhook_url="http://localhost:8000/webhook",
        )
>       assert manifest["hook_attributes"]["url"] == "http://localhost:8000/webhook"
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       KeyError: 'hook_attributes'

tests/test_manifest.py:36: KeyError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestUrlValidation::test_allows_http_localhost - KeyError: 'hook_attributes'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 122 passed, 3 deselected, 1 warning in 2.40s
operator: core/AddNot, occurrence: 4, definition_name: exchange_code_for_credentials
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -147,7 +147,7 @@
         ValueError: If code contains invalid characters
     """
     # Validate code to prevent SSRF - GitHub codes are alphanumeric
-    if not code or not code.isalnum():
+    if not not code or not code.isalnum():
         raise ValueError("Invalid manifest code format")
 
     url = GITHUB_MANIFEST_CONVERSION_URL.format(code=code)
........................................................................ [ 30%]
................................................................F
=================================== FAILURES ===================================
_________________ TestExchangeCode.test_exchange_code_success __________________

self = <tests.test_manifest.TestExchangeCode object at 0x7f7bc3a7b610>

    @pytest.mark.asyncio
    async def test_exchange_code_success(self):
        """Test successful code exchange."""
        import httpx
    
        mock_response_data = {
            "id": 12345,
            "pem": "-----BEGIN RSA PRIVATE KEY-----\ntest\n-----END RSA PRIVATE KEY-----",
            "webhook_secret": "test-secret",
            "slug": "my-stampbot",
            "name": "My Stampbot",
            "client_id": "client123",
            "client_secret": "secret456",
        }
    
        # Create a proper mock response with request attached
        mock_request = httpx.Request(
            "POST", "https://api.github.com/app-manifests/testcode123/conversions"
        )
        mock_response = httpx.Response(200, json=mock_response_data, request=mock_request)
    
        with patch("httpx.AsyncClient.post", new_callable=AsyncMock) as mock_post:
            mock_post.return_value = mock_response
    
>           result = await exchange_code_for_credentials("testcode123")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_manifest.py:206: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

code = 'testcode123'

    async def exchange_code_for_credentials(code: str) -> dict[str, Any]:
        """Exchange the temporary code for app credentials.
    
        After a user creates a GitHub App from a manifest, GitHub redirects
        to the callback URL with a temporary code. This function exchanges
        that code for the actual app credentials.
    
        Args:
            code: Temporary code from GitHub callback
    
        Returns:
            Dictionary with app credentials:
            - id: App ID
            - pem: Private key (PEM format)
            - webhook_secret: Webhook secret
            - slug: App slug
            - name: App name
            - client_id: OAuth client ID
            - client_secret: OAuth client secret
    
        Raises:
            httpx.HTTPStatusError: If API call fails
            ValueError: If code contains invalid characters
        """
        # Validate code to prevent SSRF - GitHub codes are alphanumeric
        if not not code or not code.isalnum():
>           raise ValueError("Invalid manifest code format")
E           ValueError: Invalid manifest code format

stampbot/manifest.py:151: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestExchangeCode::test_exchange_code_success - ValueError: Invalid manifest code format
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 136 passed, 3 deselected, 1 warning in 2.44s
operator: core/ReplaceTrueWithFalse, occurrence: 0, definition_name: create_manifest
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -102,7 +102,7 @@
         _validate_url(webhook_url, "webhook_url")
         manifest["hook_attributes"] = {
             "url": webhook_url,
-            "active": True,
+            "active": False,
         }
 
     return manifest
........................................................................ [ 30%]
.......................................................F
=================================== FAILURES ===================================
__________ TestCreateManifest.test_manifest_webhook_url_when_provided __________

self = <tests.test_manifest.TestCreateManifest object at 0x7fd58b2d7950>

    def test_manifest_webhook_url_when_provided(self):
        """Test manifest contains webhook URL when provided."""
        manifest = create_manifest(
            redirect_url="https://stampbot.example.com/setup/callback",
            webhook_url="https://stampbot.example.com/webhook",
        )
    
        assert manifest["hook_attributes"]["url"] == "https://stampbot.example.com/webhook"
>       assert manifest["hook_attributes"]["active"] is True
E       assert False is True

tests/test_manifest.py:94: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestCreateManifest::test_manifest_webhook_url_when_provided - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 127 passed, 3 deselected, 1 warning in 2.41s
operator: core/ReplaceFalseWithTrue, occurrence: 0, definition_name: create_manifest
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -92,7 +92,7 @@
         "description": app_description,
         "url": base_url,
         "redirect_url": redirect_url,
-        "public": False,
+        "public": True,
         "default_permissions": MANIFEST_PERMISSIONS,
         "default_events": MANIFEST_EVENTS,
     }
........................................................................ [ 30%]
...........................................................F
=================================== FAILURES ===================================
_________________ TestCreateManifest.test_manifest_is_private __________________

self = <tests.test_manifest.TestCreateManifest object at 0x7fc2dd447350>

    def test_manifest_is_private(self):
        """Test manifest creates private app."""
        manifest = create_manifest(
            redirect_url="https://example.com/setup/callback",
        )
    
>       assert manifest["public"] is False
E       assert True is False

tests/test_manifest.py:126: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestCreateManifest::test_manifest_is_private - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 131 passed, 3 deselected, 1 warning in 2.39s
operator: core/ReplaceOrWithAnd, occurrence: 0, definition_name: _validate_url
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -27,7 +27,7 @@
     """
     parsed = urlparse(url)
 
-    if not parsed.scheme or not parsed.netloc:
+    if not parsed.scheme and not parsed.netloc:
         raise ValueError(f"Invalid {name}: must be a complete URL")
 
     # Allow http only for localhost (development)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceOrWithAnd, occurrence: 1, definition_name: exchange_code_for_credentials
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -147,7 +147,7 @@
         ValueError: If code contains invalid characters
     """
     # Validate code to prevent SSRF - GitHub codes are alphanumeric
-    if not code or not code.isalnum():
+    if not code and not code.isalnum():
         raise ValueError("Invalid manifest code format")
 
     url = GITHUB_MANIFEST_CONVERSION_URL.format(code=code)
........................................................................ [ 30%]
...................................................................F
=================================== FAILURES ===================================
________ TestExchangeCode.test_exchange_code_rejects_invalid_characters ________

self = <tests.test_manifest.TestExchangeCode object at 0x7fd7510bbe10>

    @pytest.mark.asyncio
    async def test_exchange_code_rejects_invalid_characters(self):
        """Test that code with special characters raises ValueError to prevent SSRF."""
        with pytest.raises(ValueError, match="Invalid manifest code format"):
>           await exchange_code_for_credentials("../../../etc/passwd")

tests/test_manifest.py:245: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/manifest.py:165: in exchange_code_for_credentials
    response.raise_for_status()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Response [404 Not Found]>

    def raise_for_status(self) -> Response:
        """
        Raise the `HTTPStatusError` if one occurred.
        """
        request = self._request
        if request is None:
            raise RuntimeError(
                "Cannot call `raise_for_status` as the request "
                "instance has not been set on this response."
            )
    
        if self.is_success:
            return self
    
        if self.has_redirect_location:
            message = (
                "{error_type} '{0.status_code} {0.reason_phrase}' for url '{0.url}'\n"
                "Redirect location: '{0.headers[location]}'\n"
                "For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/{0.status_code}"
            )
        else:
            message = (
                "{error_type} '{0.status_code} {0.reason_phrase}' for url '{0.url}'\n"
                "For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/{0.status_code}"
            )
    
        status_class = self.status_code // 100
        error_types = {
            1: "Informational response",
            3: "Redirect response",
            4: "Client error",
            5: "Server error",
        }
        error_type = error_types.get(status_class, "Invalid status code")
        message = message.format(self, error_type=error_type)
>       raise HTTPStatusError(message, request=request, response=self)
E       httpx.HTTPStatusError: Client error '404 Not Found' for url 'https://api.github.com/etc/passwd/conversions'
E       For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404

../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_models.py:829: HTTPStatusError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:43:44.935996Z [info     ] Exchanging manifest code for credentials [stampbot.manifest] _logger=<_FixedFindCallerLogger stampbot.manifest (INFO)> _name=info
2026-06-29T05:43:44.980690Z [info     ] HTTP Request: POST https://api.github.com/etc/passwd/conversions "HTTP/1.1 404 Not Found" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.manifest:manifest.py:155 {'event': 'Exchanging manifest code for credentials', 'logger': 'stampbot.manifest', 'level': 'info', 'timestamp': '2026-06-29T05:43:44.935996Z'}
INFO     httpx:_client.py:1740 HTTP Request: POST https://api.github.com/etc/passwd/conversions "HTTP/1.1 404 Not Found"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestExchangeCode::test_exchange_code_rejects_invalid_characters - httpx.HTTPStatusError: Client error '404 Not Found' for url 'https://api.github.com/etc/passwd/conversions'
For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 139 passed, 3 deselected, 1 warning in 2.60s
operator: core/NumberReplacer, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -41,7 +41,7 @@
 # GitHub App Manifest URLs
 GITHUB_MANIFEST_URL = "https://github.com/settings/apps/new"
 GITHUB_MANIFEST_CONVERSION_URL = "https://api.github.com/app-manifests/{code}/conversions"
-GITHUB_MANIFEST_TIMEOUT_SECONDS = 10.0
+GITHUB_MANIFEST_TIMEOUT_SECONDS = 11.0
 
 # Required permissions for stampbot
 MANIFEST_PERMISSIONS = {
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/NumberReplacer, occurrence: 1, definition_name: None
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -41,7 +41,7 @@
 # GitHub App Manifest URLs
 GITHUB_MANIFEST_URL = "https://github.com/settings/apps/new"
 GITHUB_MANIFEST_CONVERSION_URL = "https://api.github.com/app-manifests/{code}/conversions"
-GITHUB_MANIFEST_TIMEOUT_SECONDS = 10.0
+GITHUB_MANIFEST_TIMEOUT_SECONDS = 9.0
 
 # Required permissions for stampbot
 MANIFEST_PERMISSIONS = {
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/NumberReplacer, occurrence: 2, definition_name: create_manifest
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -85,7 +85,7 @@
     _validate_url(redirect_url, "redirect_url")
 
     # Extract base URL from redirect URL
-    base_url = redirect_url.rsplit("/setup/callback", 1)[0]
+    base_url = redirect_url.rsplit("/setup/callback", 2)[0]
 
     manifest: dict[str, Any] = {
         "name": app_name,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/NumberReplacer, occurrence: 3, definition_name: create_manifest
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -85,7 +85,7 @@
     _validate_url(redirect_url, "redirect_url")
 
     # Extract base URL from redirect URL
-    base_url = redirect_url.rsplit("/setup/callback", 1)[0]
+    base_url = redirect_url.rsplit("/setup/callback", 0)[0]
 
     manifest: dict[str, Any] = {
         "name": app_name,
........................................................................ [ 30%]
..........................................................F
=================================== FAILURES ===================================
__________________ TestCreateManifest.test_manifest_base_url ___________________

self = <tests.test_manifest.TestCreateManifest object at 0x7fddba2d7df0>

    def test_manifest_base_url(self):
        """Test manifest contains correct base URL derived from redirect URL."""
        manifest = create_manifest(
            redirect_url="https://stampbot.example.com/setup/callback",
        )
    
>       assert manifest["url"] == "https://stampbot.example.com"
E       AssertionError: assert 'https://stam...etup/callback' == 'https://stampbot.example.com'
E         
E         - https://stampbot.example.com
E         + https://stampbot.example.com/setup/callback
E         ?                             +++++++++++++++

tests/test_manifest.py:118: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestCreateManifest::test_manifest_base_url - AssertionError: assert 'https://stam...etup/callback' == 'https://stampbot.example.com'
  
  - https://stampbot.example.com
  + https://stampbot.example.com/setup/callback
  ?                             +++++++++++++++
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 130 passed, 3 deselected, 1 warning in 2.39s
operator: core/NumberReplacer, occurrence: 4, definition_name: create_manifest
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -85,7 +85,7 @@
     _validate_url(redirect_url, "redirect_url")
 
     # Extract base URL from redirect URL
-    base_url = redirect_url.rsplit("/setup/callback", 1)[0]
+    base_url = redirect_url.rsplit("/setup/callback", 1)[ 1]
 
     manifest: dict[str, Any] = {
         "name": app_name,
........................................................................ [ 30%]
..........................................................F
=================================== FAILURES ===================================
__________________ TestCreateManifest.test_manifest_base_url ___________________

self = <tests.test_manifest.TestCreateManifest object at 0x7ff660b3bdf0>

    def test_manifest_base_url(self):
        """Test manifest contains correct base URL derived from redirect URL."""
        manifest = create_manifest(
            redirect_url="https://stampbot.example.com/setup/callback",
        )
    
>       assert manifest["url"] == "https://stampbot.example.com"
E       AssertionError: assert '' == 'https://stampbot.example.com'
E         
E         - https://stampbot.example.com

tests/test_manifest.py:118: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestCreateManifest::test_manifest_base_url - AssertionError: assert '' == 'https://stampbot.example.com'
  
  - https://stampbot.example.com
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 130 passed, 3 deselected, 1 warning in 2.40s
operator: core/NumberReplacer, occurrence: 5, definition_name: create_manifest
--- mutation diff ---
--- astampbot/manifest.py
+++ bstampbot/manifest.py
@@ -85,7 +85,7 @@
     _validate_url(redirect_url, "redirect_url")
 
     # Extract base URL from redirect URL
-    base_url = redirect_url.rsplit("/setup/callback", 1)[0]
+    base_url = redirect_url.rsplit("/setup/callback", 1)[ -1]
 
     manifest: dict[str, Any] = {
         "name": app_name,
........................................................................ [ 30%]
..........................................................F
=================================== FAILURES ===================================
__________________ TestCreateManifest.test_manifest_base_url ___________________

self = <tests.test_manifest.TestCreateManifest object at 0x7f56d3473df0>

    def test_manifest_base_url(self):
        """Test manifest contains correct base URL derived from redirect URL."""
        manifest = create_manifest(
            redirect_url="https://stampbot.example.com/setup/callback",
        )
    
>       assert manifest["url"] == "https://stampbot.example.com"
E       AssertionError: assert '' == 'https://stampbot.example.com'
E         
E         - https://stampbot.example.com

tests/test_manifest.py:118: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_manifest.py::TestCreateManifest::test_manifest_base_url - AssertionError: assert '' == 'https://stampbot.example.com'
  
  - https://stampbot.example.com
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 130 passed, 3 deselected, 1 warning in 2.41s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 0, definition_name: configure_telemetry
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -27,7 +27,7 @@
     Returns:
         TracerProvider if telemetry is enabled, None otherwise
     """
-    if not settings.otel_enabled:
+    if  settings.otel_enabled:
         logger.info("OpenTelemetry disabled")
         return None
 
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
>       from stampbot.main import app

tests/test_main.py:15: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/main.py:50: in <module>
    configure_telemetry()
stampbot/telemetry.py:34: in configure_telemetry
    if not settings.otel_endpoint:
           ^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/dynaconf/base.py:144: in __getattr__
    value = getattr(self._wrapped, name)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <dynaconf.base.Settings object at 0x7fbcf71fef90>, name = 'OTEL_ENDPOINT'

    def __getattribute__(self, name):
        if (
            name.startswith("__")
            or name in RESERVED_ATTRS + UPPER_DEFAULT_SETTINGS
        ):
            return super().__getattribute__(name)
    
        # This is to keep the only upper case mode working
        # self._store has Lazy values already evaluated
        if (
            name.islower()
            and self._store.get("LOWERCASE_READ_FOR_DYNACONF", empty) is False
        ):
            try:
                # only matches exact casing, first levels always upper
                return self._store.__getattribute__(name)
            except KeyError:
                return super().__getattribute__(name)
    
        # then go to the regular .get which triggers hooks among other things
        value = self.get(name, default=empty)
        if value is empty:
>           return super().__getattribute__(name)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           AttributeError: 'Settings' object has no attribute 'OTEL_ENDPOINT'

../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/dynaconf/base.py:332: AttributeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - AttributeError: 'Settings' object has no attribute 'OTEL_ENDPOINT'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.27s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 1, definition_name: configure_telemetry
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -31,7 +31,7 @@
         logger.info("OpenTelemetry disabled")
         return None
 
-    if not settings.otel_endpoint:
+    if  settings.otel_endpoint:
         logger.warning("OpenTelemetry enabled but no endpoint configured")
         return None
 
........................................................................ [ 30%]
........................................................................ [ 60%]
......................F
=================================== FAILURES ===================================
_____________________ test_configure_telemetry_no_endpoint _____________________

    def test_configure_telemetry_no_endpoint():
        """Test configure_telemetry returns None when no endpoint configured."""
        with patch("stampbot.telemetry.settings") as mock_settings:
            mock_settings.otel_enabled = True
            mock_settings.otel_endpoint = None
            from stampbot.telemetry import configure_telemetry
    
            result = configure_telemetry()
>           assert result is None
E           assert <opentelemetry.sdk.trace.TracerProvider object at 0x7f25f3e3a900> is None

tests/test_telemetry.py:104: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:17:42.001121Z [warning  ] Invalid type MagicMock for attribute 'service.name' value. Expected one of ['bool', 'str', 'bytes', 'int', 'float'] or a sequence of those types [opentelemetry.attributes]
2026-06-29T05:17:42.026043Z [info     ] OpenTelemetry configured with endpoint: None [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info extra={'otel_endpoint': None}
------------------------------ Captured log call -------------------------------
WARNING  opentelemetry.attributes:__init__.py:107 Invalid type MagicMock for attribute 'service.name' value. Expected one of ['bool', 'str', 'bytes', 'int', 'float'] or a sequence of those types
INFO     stampbot.telemetry:telemetry.py:62 {'extra': {'otel_endpoint': None}, 'event': 'OpenTelemetry configured with endpoint: None', 'logger': 'stampbot.telemetry', 'level': 'info', 'timestamp': '2026-06-29T05:17:42.026043Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_telemetry.py::test_configure_telemetry_no_endpoint - assert <opentelemetry.sdk.trace.TracerProvider object at 0x7f25f3e3a900> is None
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 166 passed, 3 deselected, 1 warning in 2.64s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 2, definition_name: create_span
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -124,7 +124,7 @@
             if span:
                 span.set_attribute("result", "success")
     """
-    if not settings.otel_enabled:
+    if  settings.otel_enabled:
         yield None
         return
 
........................................................................ [ 30%]
........................................................................ [ 60%]
....................F
=================================== FAILURES ===================================
_____________________ test_create_span_when_otel_disabled ______________________

    def test_create_span_when_otel_disabled():
        """Test create_span yields None when OTEL is disabled."""
        with patch("stampbot.telemetry.settings") as mock_settings:
            mock_settings.otel_enabled = False
            from stampbot.telemetry import create_span
    
            with create_span("test_span", {"attr": "value"}) as span:
>               assert span is None
E               assert NonRecordingSpan(SpanContext(trace_id=0x00000000000000000000000000000000, span_id=0x0000000000000000, trace_flags=0x00, trace_state=[], is_remote=False)) is None

tests/test_telemetry.py:83: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_telemetry.py::test_create_span_when_otel_disabled - assert NonRecordingSpan(SpanContext(trace_id=0x00000000000000000000000000000000, span_id=0x0000000000000000, trace_flags=0x00, trace_state=[], is_remote=False)) is None
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 164 passed, 3 deselected, 1 warning in 2.60s
operator: core/AddNot, occurrence: 0, definition_name: configure_telemetry
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -27,7 +27,7 @@
     Returns:
         TracerProvider if telemetry is enabled, None otherwise
     """
-    if not settings.otel_enabled:
+    if not not settings.otel_enabled:
         logger.info("OpenTelemetry disabled")
         return None
 
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
>       from stampbot.main import app

tests/test_main.py:15: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/main.py:50: in <module>
    configure_telemetry()
stampbot/telemetry.py:34: in configure_telemetry
    if not settings.otel_endpoint:
           ^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/dynaconf/base.py:144: in __getattr__
    value = getattr(self._wrapped, name)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <dynaconf.base.Settings object at 0x7f1214fcef90>, name = 'OTEL_ENDPOINT'

    def __getattribute__(self, name):
        if (
            name.startswith("__")
            or name in RESERVED_ATTRS + UPPER_DEFAULT_SETTINGS
        ):
            return super().__getattribute__(name)
    
        # This is to keep the only upper case mode working
        # self._store has Lazy values already evaluated
        if (
            name.islower()
            and self._store.get("LOWERCASE_READ_FOR_DYNACONF", empty) is False
        ):
            try:
                # only matches exact casing, first levels always upper
                return self._store.__getattribute__(name)
            except KeyError:
                return super().__getattribute__(name)
    
        # then go to the regular .get which triggers hooks among other things
        value = self.get(name, default=empty)
        if value is empty:
>           return super().__getattribute__(name)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           AttributeError: 'Settings' object has no attribute 'OTEL_ENDPOINT'

../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/dynaconf/base.py:332: AttributeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - AttributeError: 'Settings' object has no attribute 'OTEL_ENDPOINT'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.25s
operator: core/AddNot, occurrence: 1, definition_name: configure_telemetry
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -31,7 +31,7 @@
         logger.info("OpenTelemetry disabled")
         return None
 
-    if not settings.otel_endpoint:
+    if not not settings.otel_endpoint:
         logger.warning("OpenTelemetry enabled but no endpoint configured")
         return None
 
........................................................................ [ 30%]
........................................................................ [ 60%]
......................F
=================================== FAILURES ===================================
_____________________ test_configure_telemetry_no_endpoint _____________________

    def test_configure_telemetry_no_endpoint():
        """Test configure_telemetry returns None when no endpoint configured."""
        with patch("stampbot.telemetry.settings") as mock_settings:
            mock_settings.otel_enabled = True
            mock_settings.otel_endpoint = None
            from stampbot.telemetry import configure_telemetry
    
            result = configure_telemetry()
>           assert result is None
E           assert <opentelemetry.sdk.trace.TracerProvider object at 0x7f06c3146900> is None

tests/test_telemetry.py:104: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:15:31.552817Z [warning  ] Invalid type MagicMock for attribute 'service.name' value. Expected one of ['bool', 'str', 'bytes', 'int', 'float'] or a sequence of those types [opentelemetry.attributes]
2026-06-29T05:15:31.577428Z [info     ] OpenTelemetry configured with endpoint: None [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info extra={'otel_endpoint': None}
------------------------------ Captured log call -------------------------------
WARNING  opentelemetry.attributes:__init__.py:107 Invalid type MagicMock for attribute 'service.name' value. Expected one of ['bool', 'str', 'bytes', 'int', 'float'] or a sequence of those types
INFO     stampbot.telemetry:telemetry.py:62 {'extra': {'otel_endpoint': None}, 'event': 'OpenTelemetry configured with endpoint: None', 'logger': 'stampbot.telemetry', 'level': 'info', 'timestamp': '2026-06-29T05:15:31.577428Z'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_telemetry.py::test_configure_telemetry_no_endpoint - assert <opentelemetry.sdk.trace.TracerProvider object at 0x7f06c3146900> is None
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 166 passed, 3 deselected, 1 warning in 2.63s
operator: core/AddNot, occurrence: 2, definition_name: instrument_fastapi
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -78,7 +78,7 @@
     Args:
         app: FastAPI application instance
     """
-    if settings.otel_enabled:
+    if not settings.otel_enabled:
         try:
             FastAPIInstrumentor.instrument_app(app)
             logger.info("FastAPI instrumented with OpenTelemetry")
........................................................................ [ 30%]
........................................................................ [ 60%]
..........................F
=================================== FAILURES ===================================
_______________________ test_instrument_fastapi_success ________________________

    def test_instrument_fastapi_success():
        """Test instrument_fastapi instruments app when OTEL is enabled."""
        with (
            patch("stampbot.telemetry.settings") as mock_settings,
            patch("stampbot.telemetry.FastAPIInstrumentor") as mock_instrumentor,
        ):
            mock_settings.otel_enabled = True
    
            from stampbot.telemetry import instrument_fastapi
    
            mock_app = Mock()
            instrument_fastapi(mock_app)
    
>           mock_instrumentor.instrument_app.assert_called_once_with(mock_app)

tests/test_telemetry.py:176: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='FastAPIInstrumentor.instrument_app' id='139755230633264'>
args = (<Mock id='139755230634272'>,), kwargs = {}
msg = "Expected 'instrument_app' to be called once. Called 0 times."

    def assert_called_once_with(self, /, *args, **kwargs):
        """assert that the mock was called exactly once and that that call was
        with the specified arguments."""
        if not self.call_count == 1:
            msg = ("Expected '%s' to be called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'instrument_app' to be called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:997: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_telemetry.py::test_instrument_fastapi_success - AssertionError: Expected 'instrument_app' to be called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 170 passed, 3 deselected, 1 warning in 2.67s
operator: core/AddNot, occurrence: 3, definition_name: create_span
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -124,7 +124,7 @@
             if span:
                 span.set_attribute("result", "success")
     """
-    if not settings.otel_enabled:
+    if not not settings.otel_enabled:
         yield None
         return
 
........................................................................ [ 30%]
........................................................................ [ 60%]
....................F
=================================== FAILURES ===================================
_____________________ test_create_span_when_otel_disabled ______________________

    def test_create_span_when_otel_disabled():
        """Test create_span yields None when OTEL is disabled."""
        with patch("stampbot.telemetry.settings") as mock_settings:
            mock_settings.otel_enabled = False
            from stampbot.telemetry import create_span
    
            with create_span("test_span", {"attr": "value"}) as span:
>               assert span is None
E               assert NonRecordingSpan(SpanContext(trace_id=0x00000000000000000000000000000000, span_id=0x0000000000000000, trace_flags=0x00, trace_state=[], is_remote=False)) is None

tests/test_telemetry.py:83: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_telemetry.py::test_create_span_when_otel_disabled - assert NonRecordingSpan(SpanContext(trace_id=0x00000000000000000000000000000000, span_id=0x0000000000000000, trace_flags=0x00, trace_state=[], is_remote=False)) is None
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 164 passed, 3 deselected, 1 warning in 2.61s
operator: core/AddNot, occurrence: 4, definition_name: create_span
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -132,7 +132,7 @@
 
     with tracer.start_as_current_span(name) as span:
         try:
-            if attributes:
+            if not attributes:
                 for key, value in attributes.items():
                     span.set_attribute(key, value)
             yield span
........................................................................ [ 30%]
........................................................................ [ 60%]
............................F
=================================== FAILURES ===================================
_______________________ test_create_span_with_exception ________________________

    def test_create_span_with_exception():
        """Test create_span records exception when one is raised."""
        with (
            patch("stampbot.telemetry.settings") as mock_settings,
            patch("stampbot.telemetry.get_tracer") as mock_get_tracer,
        ):
            mock_settings.otel_enabled = True
    
            mock_span = Mock()
            mock_tracer = Mock()
            mock_tracer.start_as_current_span.return_value.__enter__ = Mock(return_value=mock_span)
            mock_tracer.start_as_current_span.return_value.__exit__ = Mock(return_value=False)
            mock_get_tracer.return_value = mock_tracer
    
            from stampbot.telemetry import create_span
    
            test_error = ValueError("test error")
            try:
>               with create_span("test_span"):
                     ^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_telemetry.py:213: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/contextlib.py:141: in __enter__
    return next(self.gen)
           ^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

name = 'test_span', attributes = None, record_exception = True

    @contextmanager
    def create_span(
        name: str,
        attributes: dict[str, Any] | None = None,
        record_exception: bool = True,
    ) -> Iterator[Span | None]:
        """Create a span context manager for tracing operations.
    
        This is a convenience wrapper that handles span creation, attribute setting,
        and exception recording. If OpenTelemetry is disabled, yields None and
        the code block executes without tracing.
    
        Args:
            name: Name of the span
            attributes: Optional attributes to set on the span
            record_exception: Whether to record exceptions on the span
    
        Yields:
            The span if telemetry is enabled, None otherwise
    
        Example:
            with create_span("github.approve_pr", {"repo": "owner/repo", "pr": 123}) as span:
                # do work
                if span:
                    span.set_attribute("result", "success")
        """
        if not settings.otel_enabled:
            yield None
            return
    
        tracer = get_tracer("stampbot")
    
        with tracer.start_as_current_span(name) as span:
            try:
                if not attributes:
>                   for key, value in attributes.items():
                                      ^^^^^^^^^^^^^^^^
E                   AttributeError: 'NoneType' object has no attribute 'items'

stampbot/telemetry.py:136: AttributeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_telemetry.py::test_create_span_with_exception - AttributeError: 'NoneType' object has no attribute 'items'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 172 passed, 3 deselected, 1 warning in 2.68s
operator: core/AddNot, occurrence: 5, definition_name: create_span
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -137,7 +137,7 @@
                     span.set_attribute(key, value)
             yield span
         except Exception as e:
-            if record_exception:
+            if not record_exception:
                 span.record_exception(e)
                 span.set_status(Status(StatusCode.ERROR, str(e)))
             raise
........................................................................ [ 30%]
........................................................................ [ 60%]
............................F
=================================== FAILURES ===================================
_______________________ test_create_span_with_exception ________________________

    def test_create_span_with_exception():
        """Test create_span records exception when one is raised."""
        with (
            patch("stampbot.telemetry.settings") as mock_settings,
            patch("stampbot.telemetry.get_tracer") as mock_get_tracer,
        ):
            mock_settings.otel_enabled = True
    
            mock_span = Mock()
            mock_tracer = Mock()
            mock_tracer.start_as_current_span.return_value.__enter__ = Mock(return_value=mock_span)
            mock_tracer.start_as_current_span.return_value.__exit__ = Mock(return_value=False)
            mock_get_tracer.return_value = mock_tracer
    
            from stampbot.telemetry import create_span
    
            test_error = ValueError("test error")
            try:
                with create_span("test_span"):
                    raise test_error
            except ValueError:
                pass
    
>           mock_span.record_exception.assert_called_once_with(test_error)

tests/test_telemetry.py:218: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='mock.record_exception' id='140107970796176'>
args = (ValueError('test error'),), kwargs = {}
msg = "Expected 'record_exception' to be called once. Called 0 times."

    def assert_called_once_with(self, /, *args, **kwargs):
        """assert that the mock was called exactly once and that that call was
        with the specified arguments."""
        if not self.call_count == 1:
            msg = ("Expected '%s' to be called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'record_exception' to be called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:997: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_telemetry.py::test_create_span_with_exception - AssertionError: Expected 'record_exception' to be called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 172 passed, 3 deselected, 1 warning in 2.68s
operator: core/AddNot, occurrence: 6, definition_name: set_span_error
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -150,7 +150,7 @@
         span: The span to update (can be None if telemetry disabled)
         error: The exception that occurred
     """
-    if span:
+    if not span:
         span.record_exception(error)
         span.set_status(Status(StatusCode.ERROR, str(error)))
 
.................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_failure ________

self = <stampbot.github_client.GitHubAppClient object at 0x7fba07bdf6c0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
>               auth = self.integration.get_access_token(installation_id)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:164: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='GithubIntegration().get_access_token' id='140436924549504'>
args = (123456,), kwargs = {}, effect = Exception('Token exchange failed')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Token exchange failed

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7fba09410410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            with pytest.raises(Exception, match="Token exchange failed"):
>               client._get_installation_client(123456)

tests/test_github_client.py:240: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/github_client.py:191: in _get_installation_client
    set_span_error(span, e)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

span = None, error = Exception('Token exchange failed')

    def set_span_error(span: Span | None, error: Exception) -> None:
        """Set error status on a span.
    
        Args:
            span: The span to update (can be None if telemetry disabled)
            error: The exception that occurred
        """
        if not span:
>           span.record_exception(error)
            ^^^^^^^^^^^^^^^^^^^^^
E           AttributeError: 'NoneType' object has no attribute 'record_exception'

stampbot/telemetry.py:154: AttributeError

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7fba09410410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           with pytest.raises(Exception, match="Token exchange failed"):
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           AssertionError: Regex pattern did not match.
E             Expected regex: 'Token exchange failed'
E             Actual message: "'NoneType' object has no attribute 'record_exception'"

tests/test_github_client.py:239: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_failure - AssertionError: Regex pattern did not match.
  Expected regex: 'Token exchange failed'
  Actual message: "'NoneType' object has no attribute 'record_exception'"
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 49 passed, 3 deselected, 1 warning in 2.26s
operator: core/AddNot, occurrence: 7, definition_name: set_span_ok
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -161,7 +161,7 @@
     Args:
         span: The span to update (can be None if telemetry disabled)
     """
-    if span:
+    if not span:
         span.set_status(Status(StatusCode.OK))
 
 
................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_success ________

self = <tests.test_github_client.TestGetInstallationClient object at 0x7fe75e5942d0>

    def test_get_installation_client_success(self):
        """Test successful installation client creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client._get_installation_client(123456)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:211: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/github_client.py:184: in _get_installation_client
    set_span_ok(span)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

span = None

    def set_span_ok(span: Span | None) -> None:
        """Set OK status on a span.
    
        Args:
            span: The span to update (can be None if telemetry disabled)
        """
        if not span:
>           span.set_status(Status(StatusCode.OK))
            ^^^^^^^^^^^^^^^
E           AttributeError: 'NoneType' object has no attribute 'set_status'

stampbot/telemetry.py:165: AttributeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_success - AttributeError: 'NoneType' object has no attribute 'set_status'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 48 passed, 3 deselected, 1 warning in 2.16s
operator: core/AddNot, occurrence: 8, definition_name: add_span_attributes
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -172,7 +172,7 @@
         span: The span to update (can be None if telemetry disabled)
         attributes: Attributes to add
     """
-    if span:
+    if not span:
         for key, value in attributes.items():
             span.set_attribute(key, value)
 
....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_success _____________________

self = <tests.test_github_client.TestApprovePR object at 0x7fe8217207d0>

    def test_approve_pr_success(self):
        """Test successful PR approval."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.approve_pr(123456, "owner/repo", 42)
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:313: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:49:58 [error    ] Failed to approve PR #42 in owner/repo: 'NoneType' object has no attribute 'set_attribute' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "'NoneType' object has no attribute 'set_attribute'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 52 passed, 3 deselected, 1 warning in 2.12s
operator: core/ReplaceTrueWithFalse, occurrence: 0, definition_name: configure_telemetry
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -50,7 +50,7 @@
         # Create OTLP exporter
         otlp_exporter = OTLPSpanExporter(
             endpoint=settings.otel_endpoint,
-            insecure=True,  # Use TLS in production
+            insecure=False,  # Use TLS in production
         )
 
         # Add span processor
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceTrueWithFalse, occurrence: 1, definition_name: create_span
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -102,7 +102,7 @@
 def create_span(
     name: str,
     attributes: dict[str, Any] | None = None,
-    record_exception: bool = True,
+    record_exception: bool = False,
 ) -> Iterator[Span | None]:
     """Create a span context manager for tracing operations.
 
........................................................................ [ 30%]
........................................................................ [ 60%]
............................F
=================================== FAILURES ===================================
_______________________ test_create_span_with_exception ________________________

    def test_create_span_with_exception():
        """Test create_span records exception when one is raised."""
        with (
            patch("stampbot.telemetry.settings") as mock_settings,
            patch("stampbot.telemetry.get_tracer") as mock_get_tracer,
        ):
            mock_settings.otel_enabled = True
    
            mock_span = Mock()
            mock_tracer = Mock()
            mock_tracer.start_as_current_span.return_value.__enter__ = Mock(return_value=mock_span)
            mock_tracer.start_as_current_span.return_value.__exit__ = Mock(return_value=False)
            mock_get_tracer.return_value = mock_tracer
    
            from stampbot.telemetry import create_span
    
            test_error = ValueError("test error")
            try:
                with create_span("test_span"):
                    raise test_error
            except ValueError:
                pass
    
>           mock_span.record_exception.assert_called_once_with(test_error)

tests/test_telemetry.py:218: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='mock.record_exception' id='139865008151184'>
args = (ValueError('test error'),), kwargs = {}
msg = "Expected 'record_exception' to be called once. Called 0 times."

    def assert_called_once_with(self, /, *args, **kwargs):
        """assert that the mock was called exactly once and that that call was
        with the specified arguments."""
        if not self.call_count == 1:
            msg = ("Expected '%s' to be called once. Called %s times.%s"
                   % (self._mock_name or 'mock',
                      self.call_count,
                      self._calls_repr()))
>           raise AssertionError(msg)
E           AssertionError: Expected 'record_exception' to be called once. Called 0 times.

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:997: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_telemetry.py::test_create_span_with_exception - AssertionError: Expected 'record_exception' to be called once. Called 0 times.
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 172 passed, 3 deselected, 1 warning in 2.66s
operator: core/ExceptionReplacer, occurrence: 0, definition_name: configure_telemetry
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -67,7 +67,7 @@
 
         return provider
 
-    except Exception as e:
+    except CosmicRayTestingException as e:
         logger.error("Failed to configure OpenTelemetry: %s", e, extra={"error": str(e)})
         return None
 
........................................................................ [ 30%]
........................................................................ [ 60%]
.........................F
=================================== FAILURES ===================================
______________________ test_configure_telemetry_exception ______________________

    def configure_telemetry() -> TracerProvider | None:
        """Configure OpenTelemetry if enabled.
    
        Returns:
            TracerProvider if telemetry is enabled, None otherwise
        """
        if not settings.otel_enabled:
            logger.info("OpenTelemetry disabled")
            return None
    
        if not settings.otel_endpoint:
            logger.warning("OpenTelemetry enabled but no endpoint configured")
            return None
    
        try:
            # Create resource
>           resource = Resource.create(
                {
                    "service.name": settings.otel_service_name,
                    "service.version": "0.1.0",
                }
            )

stampbot/telemetry.py:40: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='Resource.create' id='139791749568832'>
args = ({'service.name': <MagicMock name='settings.otel_service_name' id='139791749567824'>, 'service.version': '0.1.0'},)
kwargs = {}, effect = Exception('Connection failed')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Connection failed

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

    def test_configure_telemetry_exception():
        """Test configure_telemetry handles exceptions gracefully."""
        with (
            patch("stampbot.telemetry.settings") as mock_settings,
            patch("stampbot.telemetry.Resource") as mock_resource,
        ):
            mock_settings.otel_enabled = True
            mock_settings.otel_endpoint = "http://localhost:4317"
            mock_resource.create.side_effect = Exception("Connection failed")
    
            from stampbot.telemetry import configure_telemetry
    
>           result = configure_telemetry()
                     ^^^^^^^^^^^^^^^^^^^^^

tests/test_telemetry.py:159: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    def configure_telemetry() -> TracerProvider | None:
        """Configure OpenTelemetry if enabled.
    
        Returns:
            TracerProvider if telemetry is enabled, None otherwise
        """
        if not settings.otel_enabled:
            logger.info("OpenTelemetry disabled")
            return None
    
        if not settings.otel_endpoint:
            logger.warning("OpenTelemetry enabled but no endpoint configured")
            return None
    
        try:
            # Create resource
            resource = Resource.create(
                {
                    "service.name": settings.otel_service_name,
                    "service.version": "0.1.0",
                }
            )
    
            # Create tracer provider
            provider = TracerProvider(resource=resource)
    
            # Create OTLP exporter
            otlp_exporter = OTLPSpanExporter(
                endpoint=settings.otel_endpoint,
                insecure=True,  # Use TLS in production
            )
    
            # Add span processor
            provider.add_span_processor(BatchSpanProcessor(otlp_exporter))
    
            # Set as global tracer provider
            trace.set_tracer_provider(provider)
    
            logger.info(
                "OpenTelemetry configured with endpoint: %s",
                settings.otel_endpoint,
                extra={"otel_endpoint": settings.otel_endpoint},
            )
    
            return provider
    
>       except CosmicRayTestingException as e:
               ^^^^^^^^^^^^^^^^^^^^^^^^^
E       NameError: name 'CosmicRayTestingException' is not defined

stampbot/telemetry.py:70: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_telemetry.py::test_configure_telemetry_exception - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 169 passed, 3 deselected, 1 warning in 2.84s
operator: core/ExceptionReplacer, occurrence: 1, definition_name: instrument_fastapi
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -82,7 +82,7 @@
         try:
             FastAPIInstrumentor.instrument_app(app)
             logger.info("FastAPI instrumented with OpenTelemetry")
-        except Exception as e:
+        except CosmicRayTestingException as e:
             logger.error("Failed to instrument FastAPI: %s", e, extra={"error": str(e)})
 
 
........................................................................ [ 30%]
........................................................................ [ 60%]
...........................F
=================================== FAILURES ===================================
______________________ test_instrument_fastapi_exception _______________________

app = <Mock id='140244175562336'>

    def instrument_fastapi(app: Any) -> None:
        """Instrument FastAPI app with OpenTelemetry.
    
        Args:
            app: FastAPI application instance
        """
        if settings.otel_enabled:
            try:
>               FastAPIInstrumentor.instrument_app(app)

stampbot/telemetry.py:83: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='FastAPIInstrumentor.instrument_app' id='140244174597024'>
args = (<Mock id='140244175562336'>,), kwargs = {}
effect = Exception('Instrumentation failed')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Instrumentation failed

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

    def test_instrument_fastapi_exception():
        """Test instrument_fastapi handles exceptions gracefully."""
        with (
            patch("stampbot.telemetry.settings") as mock_settings,
            patch("stampbot.telemetry.FastAPIInstrumentor") as mock_instrumentor,
        ):
            mock_settings.otel_enabled = True
            mock_instrumentor.instrument_app.side_effect = Exception("Instrumentation failed")
    
            from stampbot.telemetry import instrument_fastapi
    
            mock_app = Mock()
            # Should not raise
>           instrument_fastapi(mock_app)

tests/test_telemetry.py:192: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

app = <Mock id='140244175562336'>

    def instrument_fastapi(app: Any) -> None:
        """Instrument FastAPI app with OpenTelemetry.
    
        Args:
            app: FastAPI application instance
        """
        if settings.otel_enabled:
            try:
                FastAPIInstrumentor.instrument_app(app)
                logger.info("FastAPI instrumented with OpenTelemetry")
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/telemetry.py:85: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_telemetry.py::test_instrument_fastapi_exception - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 171 passed, 3 deselected, 1 warning in 2.76s
operator: core/ExceptionReplacer, occurrence: 2, definition_name: create_span
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -136,7 +136,7 @@
                 for key, value in attributes.items():
                     span.set_attribute(key, value)
             yield span
-        except Exception as e:
+        except CosmicRayTestingException as e:
             if record_exception:
                 span.record_exception(e)
                 span.set_status(Status(StatusCode.ERROR, str(e)))
........................................................................ [ 30%]
........................................................................ [ 60%]
............................F
=================================== FAILURES ===================================
_______________________ test_create_span_with_exception ________________________

    def test_create_span_with_exception():
        """Test create_span records exception when one is raised."""
        with (
            patch("stampbot.telemetry.settings") as mock_settings,
            patch("stampbot.telemetry.get_tracer") as mock_get_tracer,
        ):
            mock_settings.otel_enabled = True
    
            mock_span = Mock()
            mock_tracer = Mock()
            mock_tracer.start_as_current_span.return_value.__enter__ = Mock(return_value=mock_span)
            mock_tracer.start_as_current_span.return_value.__exit__ = Mock(return_value=False)
            mock_get_tracer.return_value = mock_tracer
    
            from stampbot.telemetry import create_span
    
            test_error = ValueError("test error")
            try:
                with create_span("test_span"):
>                   raise test_error
E                   ValueError: test error

tests/test_telemetry.py:214: ValueError

During handling of the above exception, another exception occurred:

    def test_create_span_with_exception():
        """Test create_span records exception when one is raised."""
        with (
            patch("stampbot.telemetry.settings") as mock_settings,
            patch("stampbot.telemetry.get_tracer") as mock_get_tracer,
        ):
            mock_settings.otel_enabled = True
    
            mock_span = Mock()
            mock_tracer = Mock()
            mock_tracer.start_as_current_span.return_value.__enter__ = Mock(return_value=mock_span)
            mock_tracer.start_as_current_span.return_value.__exit__ = Mock(return_value=False)
            mock_get_tracer.return_value = mock_tracer
    
            from stampbot.telemetry import create_span
    
            test_error = ValueError("test error")
            try:
>               with create_span("test_span"):
                     ^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_telemetry.py:213: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/contextlib.py:162: in __exit__
    self.gen.throw(value)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

name = 'test_span', attributes = None, record_exception = True

    @contextmanager
    def create_span(
        name: str,
        attributes: dict[str, Any] | None = None,
        record_exception: bool = True,
    ) -> Iterator[Span | None]:
        """Create a span context manager for tracing operations.
    
        This is a convenience wrapper that handles span creation, attribute setting,
        and exception recording. If OpenTelemetry is disabled, yields None and
        the code block executes without tracing.
    
        Args:
            name: Name of the span
            attributes: Optional attributes to set on the span
            record_exception: Whether to record exceptions on the span
    
        Yields:
            The span if telemetry is enabled, None otherwise
    
        Example:
            with create_span("github.approve_pr", {"repo": "owner/repo", "pr": 123}) as span:
                # do work
                if span:
                    span.set_attribute("result", "success")
        """
        if not settings.otel_enabled:
            yield None
            return
    
        tracer = get_tracer("stampbot")
    
        with tracer.start_as_current_span(name) as span:
            try:
                if attributes:
                    for key, value in attributes.items():
                        span.set_attribute(key, value)
                yield span
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/telemetry.py:139: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_telemetry.py::test_create_span_with_exception - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 172 passed, 3 deselected, 1 warning in 2.66s
operator: core/RemoveDecorator, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -96,9 +96,6 @@
         Tracer instance (no-op if telemetry disabled)
     """
     return trace.get_tracer(name)
-
-
-@contextmanager
 def create_span(
     name: str,
     attributes: dict[str, Any] | None = None,
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7f609fc7ecf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
>       assert response.status_code == 200
E       assert 500 == 200
E        +  where 500 = <Response [500 Internal Server Error]>.status_code

tests/test_main.py:217: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:45:25.543023Z [error    ] Error handling webhook event: 'generator' object does not support the context manager protocol (missed __exit__ method) [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=error client_ip=testclient extra={'error': "'generator' object does not support the context manager protocol (missed __exit__ method)"}
2026-06-29T05:45:25.543868Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 500 Internal Server Error" [httpx]
------------------------------ Captured log call -------------------------------
ERROR    stampbot.main:main.py:367 {'extra': {'error': "'generator' object does not support the context manager protocol (missed __exit__ method)"}, 'event': "Error handling webhook event: 'generator' object does not support the context manager protocol (missed __exit__ method)", 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'error', 'timestamp': '2026-06-29T05:45:25.543023Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 500 Internal Server Error"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - assert 500 == 200
 +  where 500 = <Response [500 Internal Server Error]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.36s
operator: core/ZeroIterationForLoop, occurrence: 0, definition_name: create_span
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -133,7 +133,7 @@
     with tracer.start_as_current_span(name) as span:
         try:
             if attributes:
-                for key, value in attributes.items():
+                for key, value in []:
                     span.set_attribute(key, value)
             yield span
         except Exception as e:
........................................................................ [ 30%]
........................................................................ [ 60%]
.............................F
=================================== FAILURES ===================================
________________ test_create_span_with_attributes_when_enabled _________________

    def test_create_span_with_attributes_when_enabled():
        """Test create_span sets attributes on span when OTEL is enabled."""
        with (
            patch("stampbot.telemetry.settings") as mock_settings,
            patch("stampbot.telemetry.get_tracer") as mock_get_tracer,
        ):
            mock_settings.otel_enabled = True
    
            mock_span = Mock()
            mock_tracer = Mock()
            mock_tracer.start_as_current_span.return_value.__enter__ = Mock(return_value=mock_span)
            mock_tracer.start_as_current_span.return_value.__exit__ = Mock(return_value=False)
            mock_get_tracer.return_value = mock_tracer
    
            from stampbot.telemetry import create_span
    
            with create_span("test_span", {"key1": "value1", "key2": "value2"}) as span:
                assert span == mock_span
    
            # Verify attributes were set on the span
>           assert mock_span.set_attribute.call_count == 2
E           AssertionError: assert 0 == 2
E            +  where 0 = <Mock name='mock.set_attribute' id='140213010640448'>.call_count
E            +    where <Mock name='mock.set_attribute' id='140213010640448'> = <Mock id='140213010637424'>.set_attribute

tests/test_telemetry.py:242: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_telemetry.py::test_create_span_with_attributes_when_enabled - AssertionError: assert 0 == 2
 +  where 0 = <Mock name='mock.set_attribute' id='140213010640448'>.call_count
 +    where <Mock name='mock.set_attribute' id='140213010640448'> = <Mock id='140213010637424'>.set_attribute
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 173 passed, 3 deselected, 1 warning in 2.61s
operator: core/ZeroIterationForLoop, occurrence: 1, definition_name: add_span_attributes
--- mutation diff ---
--- astampbot/telemetry.py
+++ bstampbot/telemetry.py
@@ -173,6 +173,6 @@
         attributes: Attributes to add
     """
     if span:
-        for key, value in attributes.items():
+        for key, value in []:
             span.set_attribute(key, value)
 
........................................................................ [ 30%]
........................................................................ [ 60%]
...................F
=================================== FAILURES ===================================
______________________ test_add_span_attributes_with_span ______________________

    def test_add_span_attributes_with_span():
        """Test add_span_attributes adds attributes to span."""
        from stampbot.telemetry import add_span_attributes
    
        mock_span = Mock()
        attributes = {"key1": "value1", "key2": "value2"}
    
        add_span_attributes(mock_span, attributes)
    
>       assert mock_span.set_attribute.call_count == 2
E       AssertionError: assert 0 == 2
E        +  where 0 = <Mock name='mock.set_attribute' id='139960805138720'>.call_count
E        +    where <Mock name='mock.set_attribute' id='139960805138720'> = <Mock id='139960805138384'>.set_attribute

tests/test_telemetry.py:71: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_telemetry.py::test_add_span_attributes_with_span - AssertionError: assert 0 == 2
 +  where 0 = <Mock name='mock.set_attribute' id='139960805138720'>.call_count
 +    where <Mock name='mock.set_attribute' id='139960805138720'> = <Mock id='139960805138384'>.set_attribute
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 163 passed, 3 deselected, 1 warning in 2.73s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 0, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -177,7 +177,7 @@
                     retry=retry,
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 1, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -185,7 +185,7 @@
                 return client
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="failure").inc()
                 set_span_error(span, e)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 2, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -249,7 +249,7 @@
                     event="APPROVE",
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 3, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -269,7 +269,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 4, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -318,7 +318,7 @@
                 pr = repo.get_pull(pr_number)
                 head_sha: str = pr.head.sha
 
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 5, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -330,7 +330,7 @@
                 return head_sha
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.30s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 6, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -390,7 +390,7 @@
                 review = pr.get_review(review_id)
                 review.dismiss(message)
 
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 7, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -411,7 +411,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 8, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -466,7 +466,7 @@
 
                 content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                 if isinstance(content, list):
-                    duration = time.time() - start_time
+                    duration = time.time() + start_time
                     github_api_request_duration_seconds.labels(operation="get_file").observe(
                         duration
                     )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 9, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -475,7 +475,7 @@
                     set_span_ok(span)
                     return None
 
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 10, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -487,7 +487,7 @@
                 return content.decoded_content.decode("utf-8")
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="not_found").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.27s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 11, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -546,7 +546,7 @@
                     if review.user.login == bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 12, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -562,7 +562,7 @@
                 return bot_review_ids
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.21s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 13, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -634,7 +634,7 @@
                             }
                         )
 
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 14, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -650,7 +650,7 @@
                 return bot_reviews
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.27s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 15, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -707,7 +707,7 @@
 
                 pr.create_review(body=message, event="COMMENT")
 
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 16, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -729,7 +729,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.29s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 17, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -784,7 +784,7 @@
 
                 issue.create_comment(message)
 
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 18, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -808,7 +808,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 19, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -861,7 +861,7 @@
                 repo = client.get_repo(repo_full_name)
                 repo.get_label(label_name)
 
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 20, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -872,7 +872,7 @@
                 return True
 
             except GithubException as e:
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 21, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -897,7 +897,7 @@
                 return None
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 22, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -960,7 +960,7 @@
 
                 has_permission = permission_index >= required_index
 
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.28s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 23, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -980,7 +980,7 @@
                 return has_permission
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 24, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1071,7 +1071,7 @@
                         )
                         continue
 
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 25, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1091,7 +1091,7 @@
                 return member_teams
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() + start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.28s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 0, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -177,7 +177,7 @@
                     retry=retry,
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 1, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -185,7 +185,7 @@
                 return client
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="failure").inc()
                 set_span_error(span, e)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 2, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -249,7 +249,7 @@
                     event="APPROVE",
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 3, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -269,7 +269,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 4, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -318,7 +318,7 @@
                 pr = repo.get_pull(pr_number)
                 head_sha: str = pr.head.sha
 
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 5, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -330,7 +330,7 @@
                 return head_sha
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 6, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -390,7 +390,7 @@
                 review = pr.get_review(review_id)
                 review.dismiss(message)
 
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 7, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -411,7 +411,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 8, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -466,7 +466,7 @@
 
                 content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                 if isinstance(content, list):
-                    duration = time.time() - start_time
+                    duration = time.time() * start_time
                     github_api_request_duration_seconds.labels(operation="get_file").observe(
                         duration
                     )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 9, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -475,7 +475,7 @@
                     set_span_ok(span)
                     return None
 
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 10, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -487,7 +487,7 @@
                 return content.decoded_content.decode("utf-8")
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="not_found").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.21s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 11, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -546,7 +546,7 @@
                     if review.user.login == bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 12, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -562,7 +562,7 @@
                 return bot_review_ids
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 13, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -634,7 +634,7 @@
                             }
                         )
 
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 14, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -650,7 +650,7 @@
                 return bot_reviews
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 15, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -707,7 +707,7 @@
 
                 pr.create_review(body=message, event="COMMENT")
 
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 16, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -729,7 +729,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.28s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 17, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -784,7 +784,7 @@
 
                 issue.create_comment(message)
 
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 18, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -808,7 +808,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 19, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -861,7 +861,7 @@
                 repo = client.get_repo(repo_full_name)
                 repo.get_label(label_name)
 
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 20, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -872,7 +872,7 @@
                 return True
 
             except GithubException as e:
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 21, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -897,7 +897,7 @@
                 return None
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 22, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -960,7 +960,7 @@
 
                 has_permission = permission_index >= required_index
 
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 23, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -980,7 +980,7 @@
                 return has_permission
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 24, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1071,7 +1071,7 @@
                         )
                         continue
 
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.29s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 25, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1091,7 +1091,7 @@
                 return member_teams
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() * start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.27s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 0, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -177,7 +177,7 @@
                     retry=retry,
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 1, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -185,7 +185,7 @@
                 return client
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="failure").inc()
                 set_span_error(span, e)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 2, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -249,7 +249,7 @@
                     event="APPROVE",
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 3, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -269,7 +269,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 4, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -318,7 +318,7 @@
                 pr = repo.get_pull(pr_number)
                 head_sha: str = pr.head.sha
 
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 5, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -330,7 +330,7 @@
                 return head_sha
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.28s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 6, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -390,7 +390,7 @@
                 review = pr.get_review(review_id)
                 review.dismiss(message)
 
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 7, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -411,7 +411,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 8, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -466,7 +466,7 @@
 
                 content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                 if isinstance(content, list):
-                    duration = time.time() - start_time
+                    duration = time.time() / start_time
                     github_api_request_duration_seconds.labels(operation="get_file").observe(
                         duration
                     )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.27s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 9, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -475,7 +475,7 @@
                     set_span_ok(span)
                     return None
 
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 10, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -487,7 +487,7 @@
                 return content.decoded_content.decode("utf-8")
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="not_found").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 11, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -546,7 +546,7 @@
                     if review.user.login == bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 12, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -562,7 +562,7 @@
                 return bot_review_ids
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 13, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -634,7 +634,7 @@
                             }
                         )
 
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 14, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -650,7 +650,7 @@
                 return bot_reviews
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 15, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -707,7 +707,7 @@
 
                 pr.create_review(body=message, event="COMMENT")
 
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 16, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -729,7 +729,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 17, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -784,7 +784,7 @@
 
                 issue.create_comment(message)
 
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 18, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -808,7 +808,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 19, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -861,7 +861,7 @@
                 repo = client.get_repo(repo_full_name)
                 repo.get_label(label_name)
 
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 20, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -872,7 +872,7 @@
                 return True
 
             except GithubException as e:
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 21, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -897,7 +897,7 @@
                 return None
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 22, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -960,7 +960,7 @@
 
                 has_permission = permission_index >= required_index
 
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 23, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -980,7 +980,7 @@
                 return has_permission
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 24, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1071,7 +1071,7 @@
                         )
                         continue
 
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 25, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1091,7 +1091,7 @@
                 return member_teams
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() / start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.29s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 0, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -177,7 +177,7 @@
                     retry=retry,
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 1, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -185,7 +185,7 @@
                 return client
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="failure").inc()
                 set_span_error(span, e)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.27s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 2, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -249,7 +249,7 @@
                     event="APPROVE",
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.28s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 3, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -269,7 +269,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 4, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -318,7 +318,7 @@
                 pr = repo.get_pull(pr_number)
                 head_sha: str = pr.head.sha
 
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.28s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 5, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -330,7 +330,7 @@
                 return head_sha
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 6, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -390,7 +390,7 @@
                 review = pr.get_review(review_id)
                 review.dismiss(message)
 
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 7, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -411,7 +411,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 8, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -466,7 +466,7 @@
 
                 content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                 if isinstance(content, list):
-                    duration = time.time() - start_time
+                    duration = time.time() // start_time
                     github_api_request_duration_seconds.labels(operation="get_file").observe(
                         duration
                     )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 9, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -475,7 +475,7 @@
                     set_span_ok(span)
                     return None
 
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 10, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -487,7 +487,7 @@
                 return content.decoded_content.decode("utf-8")
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="not_found").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 11, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -546,7 +546,7 @@
                     if review.user.login == bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 12, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -562,7 +562,7 @@
                 return bot_review_ids
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 13, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -634,7 +634,7 @@
                             }
                         )
 
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 14, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -650,7 +650,7 @@
                 return bot_reviews
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 15, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -707,7 +707,7 @@
 
                 pr.create_review(body=message, event="COMMENT")
 
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 16, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -729,7 +729,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.30s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 17, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -784,7 +784,7 @@
 
                 issue.create_comment(message)
 
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 18, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -808,7 +808,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 19, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -861,7 +861,7 @@
                 repo = client.get_repo(repo_full_name)
                 repo.get_label(label_name)
 
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 20, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -872,7 +872,7 @@
                 return True
 
             except GithubException as e:
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 21, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -897,7 +897,7 @@
                 return None
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 22, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -960,7 +960,7 @@
 
                 has_permission = permission_index >= required_index
 
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 23, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -980,7 +980,7 @@
                 return has_permission
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.30s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 24, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1071,7 +1071,7 @@
                         )
                         continue
 
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 25, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1091,7 +1091,7 @@
                 return member_teams
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() // start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.21s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 0, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -177,7 +177,7 @@
                     retry=retry,
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 1, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -185,7 +185,7 @@
                 return client
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="failure").inc()
                 set_span_error(span, e)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 2, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -249,7 +249,7 @@
                     event="APPROVE",
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 3, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -269,7 +269,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 4, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -318,7 +318,7 @@
                 pr = repo.get_pull(pr_number)
                 head_sha: str = pr.head.sha
 
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 5, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -330,7 +330,7 @@
                 return head_sha
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 6, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -390,7 +390,7 @@
                 review = pr.get_review(review_id)
                 review.dismiss(message)
 
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 7, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -411,7 +411,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.28s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 8, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -466,7 +466,7 @@
 
                 content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                 if isinstance(content, list):
-                    duration = time.time() - start_time
+                    duration = time.time() % start_time
                     github_api_request_duration_seconds.labels(operation="get_file").observe(
                         duration
                     )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 9, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -475,7 +475,7 @@
                     set_span_ok(span)
                     return None
 
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 10, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -487,7 +487,7 @@
                 return content.decoded_content.decode("utf-8")
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="not_found").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 11, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -546,7 +546,7 @@
                     if review.user.login == bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 12, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -562,7 +562,7 @@
                 return bot_review_ids
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 13, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -634,7 +634,7 @@
                             }
                         )
 
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 14, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -650,7 +650,7 @@
                 return bot_reviews
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 15, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -707,7 +707,7 @@
 
                 pr.create_review(body=message, event="COMMENT")
 
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 16, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -729,7 +729,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 17, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -784,7 +784,7 @@
 
                 issue.create_comment(message)
 
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 18, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -808,7 +808,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 19, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -861,7 +861,7 @@
                 repo = client.get_repo(repo_full_name)
                 repo.get_label(label_name)
 
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="success").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 20, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -872,7 +872,7 @@
                 return True
 
             except GithubException as e:
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 21, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -897,7 +897,7 @@
                 return None
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 22, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -960,7 +960,7 @@
 
                 has_permission = permission_index >= required_index
 
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 23, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -980,7 +980,7 @@
                 return has_permission
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 24, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1071,7 +1071,7 @@
                         )
                         continue
 
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 25, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1091,7 +1091,7 @@
                 return member_teams
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() % start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 0, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -177,7 +177,7 @@
                     retry=retry,
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="success").inc()
 
................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_success ________

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f5a414682d0>

    def test_get_installation_client_success(self):
        """Test successful installation client creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client._get_installation_client(123456)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:211: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f5a3d2c58d0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
                auth = self.integration.get_access_token(installation_id)
    
                # Configure retry with exponential backoff
                retry = Retry(
                    total=GITHUB_API_RETRY_TOTAL,
                    backoff_factor=GITHUB_API_RETRY_BACKOFF,
                    status_forcelist=[500, 502, 503, 504],
                    allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                )
    
                client = Github(
                    auth=Auth.Token(auth.token),
                    timeout=GITHUB_API_TIMEOUT,
                    retry=retry,
                )
    
>               duration = time.time() ** start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               OverflowError: (34, 'Numerical result out of range')

stampbot/github_client.py:180: OverflowError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_success - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 48 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 1, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -185,7 +185,7 @@
                 return client
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="failure").inc()
                 set_span_error(span, e)
.................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_failure ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f479bd4b6c0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
>               auth = self.integration.get_access_token(installation_id)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:164: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='GithubIntegration().get_access_token' id='139945488615808'>
args = (123456,), kwargs = {}, effect = Exception('Token exchange failed')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Token exchange failed

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f479d7dc410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            with pytest.raises(Exception, match="Token exchange failed"):
>               client._get_installation_client(123456)

tests/test_github_client.py:240: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f479bd4b6c0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
                auth = self.integration.get_access_token(installation_id)
    
                # Configure retry with exponential backoff
                retry = Retry(
                    total=GITHUB_API_RETRY_TOTAL,
                    backoff_factor=GITHUB_API_RETRY_BACKOFF,
                    status_forcelist=[500, 502, 503, 504],
                    allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                )
    
                client = Github(
                    auth=Auth.Token(auth.token),
                    timeout=GITHUB_API_TIMEOUT,
                    retry=retry,
                )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                github_api_requests_total.labels(operation="get_token", status="success").inc()
    
                set_span_ok(span)
                return client
    
            except Exception as e:
>               duration = time.time() ** start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               OverflowError: (34, 'Numerical result out of range')

stampbot/github_client.py:188: OverflowError

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f479d7dc410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           with pytest.raises(Exception, match="Token exchange failed"):
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           AssertionError: Regex pattern did not match.
E             Expected regex: 'Token exchange failed'
E             Actual message: "(34, 'Numerical result out of range')"

tests/test_github_client.py:239: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_failure - AssertionError: Regex pattern did not match.
  Expected regex: 'Token exchange failed'
  Actual message: "(34, 'Numerical result out of range')"
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 49 passed, 3 deselected, 1 warning in 2.26s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 2, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -249,7 +249,7 @@
                     event="APPROVE",
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="success").inc()
 
....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_success _____________________

self = <tests.test_github_client.TestApprovePR object at 0x7f35d4dc07d0>

    def test_approve_pr_success(self):
        """Test successful PR approval."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.approve_pr(123456, "owner/repo", 42)
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:313: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:33:54 [error    ] Failed to approve PR #42 in owner/repo: (34, 'Numerical result out of range') extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "(34, 'Numerical result out of range')"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 52 passed, 3 deselected, 1 warning in 2.12s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 3, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -269,7 +269,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="failure").inc()
 
.....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_failure _____________________

self = <stampbot.github_client.GitHubAppClient object at 0x7f35873fe620>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
comment = 'Auto-approved by Stampbot'

    def approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str = "Auto-approved by Stampbot",
    ) -> bool:
        """Approve a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            comment: Review comment
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Create approval review
>               pr.create_review(
                    body=comment,
                    event="APPROVE",
                )

stampbot/github_client.py:247: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull().create_review' id='139867860388560'>
args = (), kwargs = {'body': 'Auto-approved by Stampbot', 'event': 'APPROVE'}
effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestApprovePR object at 0x7f358aa90910>

    def test_approve_pr_failure(self):
        """Test PR approval failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_pr.create_review.side_effect = Exception("API Error")
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.approve_pr(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:350: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f35873fe620>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
comment = 'Auto-approved by Stampbot'

    def approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str = "Auto-approved by Stampbot",
    ) -> bool:
        """Approve a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            comment: Review comment
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Create approval review
                pr.create_review(
                    body=comment,
                    event="APPROVE",
                )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                github_api_requests_total.labels(operation="approve", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "approved"})
                set_span_ok(span)
    
                logger.info(
                    f"Approved PR #{pr_number} in {repo_full_name}",
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() ** start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               OverflowError: (34, 'Numerical result out of range')

stampbot/github_client.py:272: OverflowError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_failure - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 53 passed, 3 deselected, 1 warning in 2.28s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 4, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -318,7 +318,7 @@
                 pr = repo.get_pull(pr_number)
                 head_sha: str = pr.head.sha
 
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="success").inc()
 
......................................................F
=================================== FAILURES ===================================
________________ TestGetPRHeadSHA.test_get_pr_head_sha_success _________________

self = <tests.test_github_client.TestGetPRHeadSHA object at 0x7f0676d98a50>

    def test_get_pr_head_sha_success(self):
        """Test successful PR head SHA lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_pr.head.sha = "current-head"
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_pr_head_sha(123456, "owner/repo", 42)
    
>           assert result == "current-head"
E           AssertionError: assert None == 'current-head'

tests/test_github_client.py:395: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:32:25 [error    ] Failed to get head SHA for PR #42 in owner/repo: (34, 'Numerical result out of range') extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "(34, 'Numerical result out of range')"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetPRHeadSHA::test_get_pr_head_sha_success - AssertionError: assert None == 'current-head'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 54 passed, 3 deselected, 1 warning in 2.13s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 5, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -330,7 +330,7 @@
                 return head_sha
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="failure").inc()
 
.......................................................F
=================================== FAILURES ===================================
_________ TestGetPRHeadSHA.test_get_pr_head_sha_returns_none_on_error __________

self = <stampbot.github_client.GitHubAppClient object at 0x7f874c6b2530>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def get_pr_head_sha(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> str | None:
        """Get the current head SHA for a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Current pull request head SHA, or None on error.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_pr_head_sha",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:317: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140219079658192'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetPRHeadSHA object at 0x7f875090cb90>

    def test_get_pr_head_sha_returns_none_on_error(self):
        """Test PR head SHA lookup returns None on API errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_pr_head_sha(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:427: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f874c6b2530>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def get_pr_head_sha(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> str | None:
        """Get the current head SHA for a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Current pull request head SHA, or None on error.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_pr_head_sha",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
                head_sha: str = pr.head.sha
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                github_api_requests_total.labels(operation="get_pull", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.head_sha": head_sha})
                set_span_ok(span)
    
                return head_sha
    
            except Exception as e:
>               duration = time.time() ** start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               OverflowError: (34, 'Numerical result out of range')

stampbot/github_client.py:333: OverflowError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetPRHeadSHA::test_get_pr_head_sha_returns_none_on_error - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 55 passed, 3 deselected, 1 warning in 2.27s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 6, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -390,7 +390,7 @@
                 review = pr.get_review(review_id)
                 review.dismiss(message)
 
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="success").inc()
 
........................................................F
=================================== FAILURES ===================================
______________ TestDismissApproval.test_dismiss_approval_success _______________

self = <tests.test_github_client.TestDismissApproval object at 0x7f4ff897ccd0>

    def test_dismiss_approval_success(self):
        """Test successful approval dismissal."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_review = Mock()
            mock_pr = Mock()
            mock_pr.get_review.return_value = mock_review
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.dismiss_approval(123456, "owner/repo", 42, 999)
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:473: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:15:35 [error    ] Failed to dismiss approval for PR #42 in owner/repo: (34, 'Numerical result out of range') extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "(34, 'Numerical result out of range')"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestDismissApproval::test_dismiss_approval_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 56 passed, 3 deselected, 1 warning in 2.12s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 7, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -411,7 +411,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="failure").inc()
 
.........................................................F
=================================== FAILURES ===================================
______________ TestDismissApproval.test_dismiss_approval_failure _______________

self = <stampbot.github_client.GitHubAppClient object at 0x7ff8069eb9d0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
review_id = 999, message = 'Approval dismissed by Stampbot'

    def dismiss_approval(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        review_id: int,
        message: str = "Approval dismissed by Stampbot",
    ) -> bool:
        """Dismiss a pull request approval.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            review_id: Review ID to dismiss
            message: Dismissal message
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.dismiss_approval",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.review_id": review_id,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get the review and dismiss it
                review = pr.get_review(review_id)
>               review.dismiss(message)

stampbot/github_client.py:391: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull().get_review().dismiss' id='140703221047248'>
args = ('Approval dismissed by Stampbot',), kwargs = {}
effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestDismissApproval object at 0x7ff809c24e10>

    def test_dismiss_approval_failure(self):
        """Test approval dismissal failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_review = Mock()
            mock_review.dismiss.side_effect = Exception("API Error")
            mock_pr = Mock()
            mock_pr.get_review.return_value = mock_review
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.dismiss_approval(123456, "owner/repo", 42, 999)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:512: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7ff8069eb9d0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
review_id = 999, message = 'Approval dismissed by Stampbot'

    def dismiss_approval(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        review_id: int,
        message: str = "Approval dismissed by Stampbot",
    ) -> bool:
        """Dismiss a pull request approval.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            review_id: Review ID to dismiss
            message: Dismissal message
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.dismiss_approval",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.review_id": review_id,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get the review and dismiss it
                review = pr.get_review(review_id)
                review.dismiss(message)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                github_api_requests_total.labels(operation="dismiss", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "dismissed"})
                set_span_ok(span)
    
                logger.info(
                    f"Dismissed approval for PR #{pr_number} in {repo_full_name}",
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                        "review_id": review_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() ** start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               OverflowError: (34, 'Numerical result out of range')

stampbot/github_client.py:414: OverflowError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestDismissApproval::test_dismiss_approval_failure - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 57 passed, 3 deselected, 1 warning in 2.26s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 8, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -466,7 +466,7 @@
 
                 content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                 if isinstance(content, list):
-                    duration = time.time() - start_time
+                    duration = time.time() ** start_time
                     github_api_request_duration_seconds.labels(operation="get_file").observe(
                         duration
                     )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 9, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -475,7 +475,7 @@
                     set_span_ok(span)
                     return None
 
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="success").inc()
 
..........................................................F
=================================== FAILURES ===================================
__________________ TestGetRepoFile.test_get_repo_file_success __________________

self = <tests.test_github_client.TestGetRepoFile object at 0x7f7c628dcf50>

    def test_get_repo_file_success(self):
        """Test successful file retrieval."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_content = Mock()
            mock_content.decoded_content = b"file content"
            mock_repo = Mock()
            mock_repo.get_contents.return_value = mock_content
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_repo_file(123456, "owner/repo", "stampbot.toml")
    
>           assert result == "file content"
E           AssertionError: assert None == 'file content'

tests/test_github_client.py:557: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:36:07 [debug    ] Could not fetch stampbot.toml from owner/repo: (34, 'Numerical result out of range') extra={'repo': 'owner/repo', 'file_path': 'stampbot.toml', 'installation_id': 123456}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetRepoFile::test_get_repo_file_success - AssertionError: assert None == 'file content'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 58 passed, 3 deselected, 1 warning in 2.13s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 10, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -487,7 +487,7 @@
                 return content.decoded_content.decode("utf-8")
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="not_found").inc()
 
............................................................F
=================================== FAILURES ===================================
___________ TestGetRepoFile.test_get_repo_file_returns_none_on_error ___________

self = <stampbot.github_client.GitHubAppClient object at 0x7f5b91d466d0>
installation_id = 123456, repo_full_name = 'owner/repo'
file_path = 'nonexistent.toml', ref = None

    def get_repo_file(
        self,
        installation_id: int,
        repo_full_name: str,
        file_path: str,
        ref: str | None = None,
    ) -> str | None:
        """Get file content from repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            file_path: Path to file in repository
            ref: Git reference (branch, tag, commit). Defaults to default branch
    
        Returns:
            File content as string, or None if not found
        """
        start_time = time.time()
    
        with create_span(
            "github.get_file",
            {
                "github.repo": repo_full_name,
                "github.file_path": file_path,
                "github.ref": ref or "default",
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
>               content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:467: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_contents' id='140031196025184'>
args = ('nonexistent.toml',), kwargs = {'ref': None}
effect = Exception('File not found')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: File not found

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetRepoFile object at 0x7f5b91d48770>

    def test_get_repo_file_returns_none_on_error(self):
        """Test that get_repo_file returns None when file not found."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_contents.side_effect = Exception("File not found")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_repo_file(123456, "owner/repo", "nonexistent.toml")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:628: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f5b91d466d0>
installation_id = 123456, repo_full_name = 'owner/repo'
file_path = 'nonexistent.toml', ref = None

    def get_repo_file(
        self,
        installation_id: int,
        repo_full_name: str,
        file_path: str,
        ref: str | None = None,
    ) -> str | None:
        """Get file content from repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            file_path: Path to file in repository
            ref: Git reference (branch, tag, commit). Defaults to default branch
    
        Returns:
            File content as string, or None if not found
        """
        start_time = time.time()
    
        with create_span(
            "github.get_file",
            {
                "github.repo": repo_full_name,
                "github.file_path": file_path,
                "github.ref": ref or "default",
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
                content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                if isinstance(content, list):
                    duration = time.time() - start_time
                    github_api_request_duration_seconds.labels(operation="get_file").observe(
                        duration
                    )
                    github_api_requests_total.labels(operation="get_file", status="not_found").inc()
                    add_span_attributes(span, {"github.result": "not_found"})
                    set_span_ok(span)
                    return None
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                github_api_requests_total.labels(operation="get_file", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "found"})
                set_span_ok(span)
    
                return content.decoded_content.decode("utf-8")
    
            except Exception as e:
>               duration = time.time() ** start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               OverflowError: (34, 'Numerical result out of range')

stampbot/github_client.py:490: OverflowError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetRepoFile::test_get_repo_file_returns_none_on_error - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 60 passed, 3 deselected, 1 warning in 2.29s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 11, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -546,7 +546,7 @@
                     if review.user.login == bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7f68507691d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [] == [123]
E             
E             Right contains one more item: 123
E             
E             Full diff:
E             + []
E             - [
E             -     123,
E             - ]

tests/test_github_client.py:685: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:29:55 [error    ] Failed to find bot reviews for PR #42 in owner/repo: (34, 'Numerical result out of range') extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "(34, 'Numerical result out of range')"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [] == [123]
  
  Right contains one more item: 123
  
  Full diff:
  + []
  - [
  -     123,
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 12, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -562,7 +562,7 @@
                 return bot_review_ids
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
..............................................................F
=================================== FAILURES ===================================
_______ TestFindBotReviews.test_find_bot_reviews_returns_empty_on_error ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f544cb889b0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[int]:
        """Find all reviews created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            List of review IDs created by the bot
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:535: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140000041464704'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestFindBotReviews object at 0x7f545115d310>

    def test_find_bot_reviews_returns_empty_on_error(self):
        """Test that find_bot_reviews returns empty list on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.find_bot_reviews(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:717: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f544cb889b0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[int]:
        """Find all reviews created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            List of review IDs created by the bot
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get bot user via JWT-authenticated integration (installation tokens
                # cannot call GET /user, which is restricted by GitHub Apps integration)
                app_info = self.integration.get_app()
                bot_user = f"{app_info.slug}[bot]"
    
                # Find all reviews by bot that are approvals
                bot_review_ids = []
                for review in pr.get_reviews():
                    if review.user.login == bot_user and review.state == "APPROVED":
                        bot_review_ids.append(review.id)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                    duration
                )
                github_api_requests_total.labels(operation="find_reviews", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span, {"github.reviews_found": len(bot_review_ids), "github.bot_user": bot_user}
                )
                set_span_ok(span)
    
                return bot_review_ids
    
            except Exception as e:
>               duration = time.time() ** start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               OverflowError: (34, 'Numerical result out of range')

stampbot/github_client.py:565: OverflowError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_returns_empty_on_error - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 62 passed, 3 deselected, 1 warning in 2.30s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 13, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -634,7 +634,7 @@
                             }
                         )
 
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
...............................................................F
=================================== FAILURES ===================================
______ TestFindBotApprovalReviews.test_find_bot_approval_reviews_success _______

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7f5d2b5dd450>

    def test_find_bot_approval_reviews_success(self):
        """Test successful bot approval review state lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            bot_approved_review = Mock()
            bot_approved_review.user.login = "stampbot[bot]"
            bot_approved_review.state = "APPROVED"
            bot_approved_review.id = 123
            bot_approved_review.commit_id = "headsha"
    
            bot_dismissed_review = Mock()
            bot_dismissed_review.user.login = "stampbot[bot]"
            bot_dismissed_review.state = "DISMISSED"
            bot_dismissed_review.id = 124
            bot_dismissed_review.commit_id = "oldsha"
    
            bot_commented_review = Mock()
            bot_commented_review.user.login = "stampbot[bot]"
            bot_commented_review.state = "COMMENTED"
            bot_commented_review.id = 125
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [
                bot_approved_review,
                bot_dismissed_review,
                bot_commented_review,
                other_review,
            ]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
    
>           assert result == [
                {"id": 123, "state": "APPROVED", "commit_id": "headsha"},
                {"id": 124, "state": "DISMISSED", "commit_id": "oldsha"},
            ]
E           AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
E             
E             Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
E             
E             Full diff:
E             + []
E             - [
E             -     {
E             -         'commit_id': 'headsha',
E             -         'id': 123,
E             -         'state': 'APPROVED',
E             -     },
E             -     {
E             -         'commit_id': 'oldsha',
E             -         'id': 124,
E             -         'state': 'DISMISSED',
E             -     },
E             - ]

tests/test_github_client.py:790: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:03:00 [error    ] Failed to find bot approval reviews for PR #42 in owner/repo: (34, 'Numerical result out of range') extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "(34, 'Numerical result out of range')"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_success - AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
  
  Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
  
  Full diff:
  + []
  - [
  -     {
  -         'commit_id': 'headsha',
  -         'id': 123,
  -         'state': 'APPROVED',
  -     },
  -     {
  -         'commit_id': 'oldsha',
  -         'id': 124,
  -         'state': 'DISMISSED',
  -     },
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 63 passed, 3 deselected, 1 warning in 2.18s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 14, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -650,7 +650,7 @@
                 return bot_reviews
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
................................................................F
=================================== FAILURES ===================================
_ TestFindBotApprovalReviews.test_find_bot_approval_reviews_returns_empty_on_error _

self = <stampbot.github_client.GitHubAppClient object at 0x7f967820be30>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_approval_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[BotReview]:
        """Find approval review states created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Review state details for bot approval reviews.
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_approval_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:615: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140284237286768'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7f967c761590>

    def test_find_bot_approval_reviews_returns_empty_on_error(self):
        """Test that find_bot_approval_reviews returns empty list on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:825: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f967820be30>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_approval_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[BotReview]:
        """Find approval review states created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Review state details for bot approval reviews.
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_approval_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get bot user via JWT-authenticated integration (installation tokens
                # cannot call GET /user, which is restricted by GitHub Apps integration)
                app_info = self.integration.get_app()
                bot_user = f"{app_info.slug}[bot]"
    
                bot_reviews: list[BotReview] = []
                for review in pr.get_reviews():
                    if review.user.login == bot_user and review.state in (
                        "APPROVED",
                        "DISMISSED",
                    ):
                        bot_reviews.append(
                            {
                                "id": review.id,
                                "state": review.state,
                                "commit_id": getattr(review, "commit_id", None),
                            }
                        )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                    duration
                )
                github_api_requests_total.labels(operation="find_reviews", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span, {"github.reviews_found": len(bot_reviews), "github.bot_user": bot_user}
                )
                set_span_ok(span)
    
                return bot_reviews
    
            except Exception as e:
>               duration = time.time() ** start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               OverflowError: (34, 'Numerical result out of range')

stampbot/github_client.py:653: OverflowError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_returns_empty_on_error - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 64 passed, 3 deselected, 1 warning in 2.29s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 15, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -707,7 +707,7 @@
 
                 pr.create_review(body=message, event="COMMENT")
 
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="success").inc()
 
........................................................................ [ 30%]
......F
=================================== FAILURES ===================================
_______ TestCreatePrReviewComment.test_create_pr_review_comment_success ________

self = <tests.test_github_client.TestCreatePrReviewComment object at 0x7faa88389e50>

    def test_create_pr_review_comment_success(self):
        """Test successful review comment creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_pr_review_comment(
                123456,
                "owner/repo",
                42,
                "Config error",
            )
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:1398: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:35:08 [warning  ] Failed to post config error review for PR #42 in owner/repo: (34, 'Numerical result out of range') extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "(34, 'Numerical result out of range')"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreatePrReviewComment::test_create_pr_review_comment_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 78 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 16, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -729,7 +729,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="failure").inc()
 
........................................................................ [ 30%]
.......F
=================================== FAILURES ===================================
_______ TestCreatePrReviewComment.test_create_pr_review_comment_failure ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f9e11efb2f0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
message = 'Config error'

    def create_pr_review_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
    ) -> bool:
        """Create a comment review on a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            message: Review comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_review_comment",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               pr = repo.get_pull(pr_number)
                     ^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:706: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull' id='140316881680240'>
args = (42,), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestCreatePrReviewComment object at 0x7f9e16211f90>

    def test_create_pr_review_comment_failure(self):
        """Test review comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_pull.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.create_pr_review_comment(
                123456,
                "owner/repo",
                42,
                "Config error",
            )

tests/test_github_client.py:1433: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f9e11efb2f0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
message = 'Config error'

    def create_pr_review_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
    ) -> bool:
        """Create a comment review on a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            message: Review comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_review_comment",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                pr.create_review(body=message, event="COMMENT")
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                github_api_requests_total.labels(operation="comment", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "commented"})
                set_span_ok(span)
    
                logger.info(
                    "Posted config error review on PR #%d in %s",
                    pr_number,
                    repo_full_name,
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() ** start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               OverflowError: (34, 'Numerical result out of range')

stampbot/github_client.py:732: OverflowError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreatePrReviewComment::test_create_pr_review_comment_failure - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 79 passed, 3 deselected, 1 warning in 2.31s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 17, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -784,7 +784,7 @@
 
                 issue.create_comment(message)
 
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........F
=================================== FAILURES ===================================
___________ TestCreateIssueComment.test_create_issue_comment_success ___________

self = <tests.test_github_client.TestCreateIssueComment object at 0x7f496160e0d0>

    def test_create_issue_comment_success(self):
        """Test successful issue comment creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_issue = Mock()
            mock_repo = Mock()
            mock_repo.get_issue.return_value = mock_issue
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_issue_comment(
                123456,
                "owner/repo",
                42,
                "Help text",
            )
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:1487: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:05:01 [warning  ] Failed to post issue comment on #42 in owner/repo: (34, 'Numerical result out of range') extra={'repo': 'owner/repo', 'issue_number': 42, 'installation_id': 123456, 'error': "(34, 'Numerical result out of range')"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreateIssueComment::test_create_issue_comment_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 80 passed, 3 deselected, 1 warning in 2.21s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 18, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -808,7 +808,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
.........F
=================================== FAILURES ===================================
___________ TestCreateIssueComment.test_create_issue_comment_failure ___________

self = <stampbot.github_client.GitHubAppClient object at 0x7f2acb326210>
installation_id = 123456, repo_full_name = 'owner/repo', issue_number = 42
message = 'Help text'

    def create_issue_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        issue_number: int,
        message: str,
    ) -> bool:
        """Create a comment on an issue or pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            issue_number: Issue or pull request number
            message: Comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_issue_comment",
            {
                "github.repo": repo_full_name,
                "github.issue_number": issue_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               issue = repo.get_issue(issue_number)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:783: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_issue' id='139821774236240'>
args = (42,), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestCreateIssueComment object at 0x7f2acf9ca210>

    def test_create_issue_comment_failure(self):
        """Test issue comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_issue.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.create_issue_comment(
                123456,
                "owner/repo",
                42,
                "Help text",
            )

tests/test_github_client.py:1523: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f2acb326210>
installation_id = 123456, repo_full_name = 'owner/repo', issue_number = 42
message = 'Help text'

    def create_issue_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        issue_number: int,
        message: str,
    ) -> bool:
        """Create a comment on an issue or pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            issue_number: Issue or pull request number
            message: Comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_issue_comment",
            {
                "github.repo": repo_full_name,
                "github.issue_number": issue_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                issue = repo.get_issue(issue_number)
    
                issue.create_comment(message)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                    duration
                )
                github_api_requests_total.labels(operation="issue_comment", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "commented"})
                set_span_ok(span)
    
                logger.info(
                    "Posted issue comment on #%d in %s",
                    issue_number,
                    repo_full_name,
                    extra={
                        "repo": repo_full_name,
                        "issue_number": issue_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() ** start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               OverflowError: (34, 'Numerical result out of range')

stampbot/github_client.py:811: OverflowError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreateIssueComment::test_create_issue_comment_failure - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 81 passed, 3 deselected, 1 warning in 2.32s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 19, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -861,7 +861,7 @@
                 repo = client.get_repo(repo_full_name)
                 repo.get_label(label_name)
 
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="success").inc()
 
........................................................................ [ 30%]
..F
=================================== FAILURES ===================================
__________________ TestRepoHasLabel.test_repo_has_label_true ___________________

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f4c5b2a9bd0>

    def test_repo_has_label_true(self):
        """Test repo_has_label returns True when label exists."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.return_value = Mock()
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.repo_has_label(123456, "owner/repo", "autoapprove")
    
>           assert result is True
E           assert None is True

tests/test_github_client.py:1239: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:23:33 [debug    ] Could not verify label autoapprove in owner/repo: (34, 'Numerical result out of range') extra={'repo': 'owner/repo', 'label': 'autoapprove', 'installation_id': 123456, 'error': "(34, 'Numerical result out of range')"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_true - assert None is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 74 passed, 3 deselected, 1 warning in 2.16s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 20, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -872,7 +872,7 @@
                 return True
 
             except GithubException as e:
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
...F
=================================== FAILURES ===================================
________________ TestRepoHasLabel.test_repo_has_label_not_found ________________

self = <stampbot.github_client.GitHubAppClient object at 0x7f213081d5b0>
installation_id = 123456, repo_full_name = 'owner/repo', label_name = 'missing'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               repo.get_label(label_name)

stampbot/github_client.py:862: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_label' id='139780525660144'>
args = ('missing',), kwargs = {}
effect = GithubException(404 {"message": "Not Found"})

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               github.GithubException.GithubException: 404 {"message": "Not Found"}

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: GithubException

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f2134c29d10>

    def test_repo_has_label_not_found(self):
        """Test repo_has_label returns False when label is missing."""
        from github.GithubException import GithubException
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = GithubException(404, {"message": "Not Found"}, None)
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.repo_has_label(123456, "owner/repo", "missing")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1275: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f213081d5b0>
installation_id = 123456, repo_full_name = 'owner/repo', label_name = 'missing'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                repo.get_label(label_name)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.label_found": True})
                set_span_ok(span)
                return True
    
            except GithubException as e:
>               duration = time.time() ** start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               OverflowError: (34, 'Numerical result out of range')

stampbot/github_client.py:875: OverflowError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_not_found - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 75 passed, 3 deselected, 1 warning in 2.30s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 21, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -897,7 +897,7 @@
                 return None
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
.....F
=================================== FAILURES ===================================
__________________ TestRepoHasLabel.test_repo_has_label_error __________________

self = <stampbot.github_client.GitHubAppClient object at 0x7f7407cba450>
installation_id = 123456, repo_full_name = 'owner/repo'
label_name = 'autoapprove'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               repo.get_label(label_name)

stampbot/github_client.py:862: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_label' id='140136323146688'>
args = ('autoapprove',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f740be4ce90>

    def test_repo_has_label_error(self):
        """Test repo_has_label returns None on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.repo_has_label(123456, "owner/repo", "autoapprove")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1349: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f7407cba450>
installation_id = 123456, repo_full_name = 'owner/repo'
label_name = 'autoapprove'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                repo.get_label(label_name)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.label_found": True})
                set_span_ok(span)
                return True
    
            except GithubException as e:
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="failure").inc()
    
                if e.status == 404:
                    add_span_attributes(span, {"github.label_found": False})
                    set_span_ok(span)
                    return False
    
                set_span_error(span, e)
                logger.debug(
                    "Could not verify label %s in %s: %s",
                    label_name,
                    repo_full_name,
                    _sanitize_error(e),
                    extra={
                        "repo": repo_full_name,
                        "label": label_name,
                        "installation_id": installation_id,
                        "error": _sanitize_error(e),
                    },
                )
                return None
    
            except Exception as e:
>               duration = time.time() ** start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               OverflowError: (34, 'Numerical result out of range')

stampbot/github_client.py:900: OverflowError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_error - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 77 passed, 3 deselected, 1 warning in 2.33s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 22, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -960,7 +960,7 @@
 
                 has_permission = permission_index >= required_index
 
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
.................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_true ______________

self = <tests.test_github_client.TestUserHasPermission object at 0x7fbc0e40d6d0>

    def test_user_has_permission_true(self):
        """Test required permission satisfied returns True."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.return_value = "write"
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.user_has_permission(123456, "owner/repo", "alice", "write")
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:868: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:15:02 [warning  ] Failed to check collaborator permission for alice in owner/repo: (34, 'Numerical result out of range') extra={'repo': 'owner/repo', 'username': 'alice', 'installation_id': 123456, 'error': "(34, 'Numerical result out of range')"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_true - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 65 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 23, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -980,7 +980,7 @@
                 return has_permission
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
...................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_error _____________

self = <stampbot.github_client.GitHubAppClient object at 0x7ff0682015b0>
installation_id = 123456, repo_full_name = 'owner/repo', username = 'carol'
required_permission = 'maintain'

    def user_has_permission(
        self,
        installation_id: int,
        repo_full_name: str,
        username: str,
        required_permission: str,
    ) -> bool:
        """Check whether a user has required access to a repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            username: GitHub username to check
            required_permission: Minimum required repository permission
    
        Returns:
            True if user meets or exceeds required permission, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.get_collaborator_permission",
            {
                "github.repo": repo_full_name,
                "github.username": username,
                "github.required_permission": required_permission,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
>               permission = repo.get_collaborator_permission(username)
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:952: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_collaborator_permission' id='140670516044064'>
args = ('carol',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestUserHasPermission object at 0x7ff06c4708a0>

    def test_user_has_permission_error(self):
        """Test permission check returns False on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.user_has_permission(123456, "owner/repo", "carol", "maintain")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:939: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7ff0682015b0>
installation_id = 123456, repo_full_name = 'owner/repo', username = 'carol'
required_permission = 'maintain'

    def user_has_permission(
        self,
        installation_id: int,
        repo_full_name: str,
        username: str,
        required_permission: str,
    ) -> bool:
        """Check whether a user has required access to a repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            username: GitHub username to check
            required_permission: Minimum required repository permission
    
        Returns:
            True if user meets or exceeds required permission, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.get_collaborator_permission",
            {
                "github.repo": repo_full_name,
                "github.username": username,
                "github.required_permission": required_permission,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
                permission = repo.get_collaborator_permission(username)
                permission_order = ["none", "read", "triage", "write", "maintain", "admin"]
                try:
                    permission_index = permission_order.index(permission)
                    required_index = permission_order.index(required_permission)
                except ValueError:
                    permission_index = -1
                    required_index = 99
    
                has_permission = permission_index >= required_index
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_permission").observe(
                    duration
                )
                github_api_requests_total.labels(operation="get_permission", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span,
                    {
                        "github.permission": permission,
                        "github.has_permission": has_permission,
                    },
                )
                set_span_ok(span)
    
                return has_permission
    
            except Exception as e:
>               duration = time.time() ** start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               OverflowError: (34, 'Numerical result out of range')

stampbot/github_client.py:983: OverflowError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_error - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 67 passed, 3 deselected, 1 warning in 2.28s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 24, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1071,7 +1071,7 @@
                         )
                         continue
 
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
.....................................................................F
=================================== FAILURES ===================================
____________ TestGetUserTeamSlugs.test_get_user_team_slugs_success _____________

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7f4fa8d85950>

    def test_get_user_team_slugs_success(self):
        """Test successful team membership check."""
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            # Mock user
            mock_user = Mock()
            mock_user.login = "alice"
    
            # Mock team that has alice as member
            mock_team = Mock()
            mock_team.has_in_members.return_value = True
    
            # Mock org
            mock_org = Mock()
            mock_org.get_team_by_slug.return_value = mock_team
    
            mock_github = Mock()
            mock_github.get_organization.return_value = mock_org
            mock_github.get_user.return_value = mock_user
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_user_team_slugs(
                123456, "acme", "alice", ["release-team", "deploy-team"]
            )
    
>           assert result == ["release-team", "deploy-team"]
E           AssertionError: assert [] == ['release-tea...'deploy-team']
E             
E             Right contains 2 more items, first extra item: 'release-team'
E             
E             Full diff:
E             + []
E             - [
E             -     'release-team',
E             -     'deploy-team',
E             - ]

tests/test_github_client.py:1033: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:22:00 [debug    ] User alice is a member of team release-team extra={'org': 'acme', 'username': 'alice', 'team': 'release-team'}
2026-06-29 05:22:00 [debug    ] User alice is a member of team deploy-team extra={'org': 'acme', 'username': 'alice', 'team': 'deploy-team'}
2026-06-29 05:22:00 [warning  ] Failed to check team memberships for alice in acme: (34, 'Numerical result out of range') extra={'org': 'acme', 'username': 'alice', 'installation_id': 123456, 'error': "(34, 'Numerical result out of range')"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_success - AssertionError: assert [] == ['release-tea...'deploy-team']
  
  Right contains 2 more items, first extra item: 'release-team'
  
  Full diff:
  + []
  - [
  -     'release-team',
  -     'deploy-team',
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 69 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 25, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1091,7 +1091,7 @@
                 return member_teams
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ** start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
.F
=================================== FAILURES ===================================
_______ TestGetUserTeamSlugs.test_get_user_team_slugs_general_exception ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f1ac9ce4e90>
installation_id = 123456, org_name = 'acme', username = 'alice'
allowed_teams = ['release-team']

    def get_user_team_slugs(
        self,
        installation_id: int,
        org_name: str,
        username: str,
        allowed_teams: list[str],
    ) -> list[str]:
        """Get team slugs the user is a member of from the allowed teams list.
    
        Args:
            installation_id: GitHub App installation ID
            org_name: Organization name
            username: GitHub username to check
            allowed_teams: List of team slugs to check (can be "org/team" or just "team")
    
        Returns:
            List of team slugs the user is a member of
        """
        start_time = time.time()
    
        with create_span(
            "github.get_user_team_slugs",
            {
                "github.org": org_name,
                "github.username": username,
                "github.installation_id": installation_id,
                "github.teams_to_check": len(allowed_teams),
            },
        ) as span:
            member_teams: list[str] = []
    
            try:
                client = self._get_installation_client(installation_id)
>               org = client.get_organization(org_name)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:1038: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_organization' id='139753031066560'>
args = ('acme',), kwargs = {}, effect = Exception('Network error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Network error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7f1ace3e7e30>

    def test_get_user_team_slugs_general_exception(self):
        """Test team membership check with general exception."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_organization.side_effect = Exception("Network error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_user_team_slugs(123456, "acme", "alice", ["release-team"])
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1195: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f1ac9ce4e90>
installation_id = 123456, org_name = 'acme', username = 'alice'
allowed_teams = ['release-team']

    def get_user_team_slugs(
        self,
        installation_id: int,
        org_name: str,
        username: str,
        allowed_teams: list[str],
    ) -> list[str]:
        """Get team slugs the user is a member of from the allowed teams list.
    
        Args:
            installation_id: GitHub App installation ID
            org_name: Organization name
            username: GitHub username to check
            allowed_teams: List of team slugs to check (can be "org/team" or just "team")
    
        Returns:
            List of team slugs the user is a member of
        """
        start_time = time.time()
    
        with create_span(
            "github.get_user_team_slugs",
            {
                "github.org": org_name,
                "github.username": username,
                "github.installation_id": installation_id,
                "github.teams_to_check": len(allowed_teams),
            },
        ) as span:
            member_teams: list[str] = []
    
            try:
                client = self._get_installation_client(installation_id)
                org = client.get_organization(org_name)
    
                for team_ref in allowed_teams:
                    # Extract team slug (handle both "org/team" and "team" formats)
                    team_slug = team_ref.split("/")[-1] if "/" in team_ref else team_ref
    
                    try:
                        team = org.get_team_by_slug(team_slug)
                        # Check if user is a member
                        user = client.get_user(username)
                        if team.has_in_members(user):  # type: ignore[arg-type]
                            member_teams.append(team_slug)
                            logger.debug(
                                "User %s is a member of team %s",
                                username,
                                team_slug,
                                extra={
                                    "org": org_name,
                                    "username": username,
                                    "team": team_slug,
                                },
                            )
                    except GithubException as e:
                        # Team not found or no access - skip silently
                        logger.debug(
                            "Could not check team %s membership: %s",
                            team_slug,
                            e.data.get("message", str(e)) if hasattr(e, "data") else str(e),
                            extra={
                                "org": org_name,
                                "team": team_slug,
                                "username": username,
                            },
                        )
                        continue
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                    duration
                )
                github_api_requests_total.labels(operation="get_user_teams", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span,
                    {
                        "github.member_teams": len(member_teams),
                        "github.teams_checked": len(allowed_teams),
                    },
                )
                set_span_ok(span)
    
                return member_teams
    
            except Exception as e:
>               duration = time.time() ** start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               OverflowError: (34, 'Numerical result out of range')

stampbot/github_client.py:1094: OverflowError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_general_exception - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 73 passed, 3 deselected, 1 warning in 2.32s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 0, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -177,7 +177,7 @@
                     retry=retry,
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="success").inc()
 
................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_success ________

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f646bec42d0>

    def test_get_installation_client_success(self):
        """Test successful installation client creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client._get_installation_client(123456)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:211: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f64678f98d0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
                auth = self.integration.get_access_token(installation_id)
    
                # Configure retry with exponential backoff
                retry = Retry(
                    total=GITHUB_API_RETRY_TOTAL,
                    backoff_factor=GITHUB_API_RETRY_BACKOFF,
                    status_forcelist=[500, 502, 503, 504],
                    allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                )
    
                client = Github(
                    auth=Auth.Token(auth.token),
                    timeout=GITHUB_API_TIMEOUT,
                    retry=retry,
                )
    
>               duration = time.time() >> start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/github_client.py:180: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_success - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 48 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 1, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -185,7 +185,7 @@
                 return client
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="failure").inc()
                 set_span_error(span, e)
.................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_failure ________

self = <stampbot.github_client.GitHubAppClient object at 0x7fd87fe9f6c0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
>               auth = self.integration.get_access_token(installation_id)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:164: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='GithubIntegration().get_access_token' id='140567789980032'>
args = (123456,), kwargs = {}, effect = Exception('Token exchange failed')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Token exchange failed

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7fd881684410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            with pytest.raises(Exception, match="Token exchange failed"):
>               client._get_installation_client(123456)

tests/test_github_client.py:240: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fd87fe9f6c0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
                auth = self.integration.get_access_token(installation_id)
    
                # Configure retry with exponential backoff
                retry = Retry(
                    total=GITHUB_API_RETRY_TOTAL,
                    backoff_factor=GITHUB_API_RETRY_BACKOFF,
                    status_forcelist=[500, 502, 503, 504],
                    allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                )
    
                client = Github(
                    auth=Auth.Token(auth.token),
                    timeout=GITHUB_API_TIMEOUT,
                    retry=retry,
                )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                github_api_requests_total.labels(operation="get_token", status="success").inc()
    
                set_span_ok(span)
                return client
    
            except Exception as e:
>               duration = time.time() >> start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/github_client.py:188: TypeError

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7fd881684410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           with pytest.raises(Exception, match="Token exchange failed"):
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           AssertionError: Regex pattern did not match.
E             Expected regex: 'Token exchange failed'
E             Actual message: "unsupported operand type(s) for >>: 'float' and 'float'"

tests/test_github_client.py:239: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_failure - AssertionError: Regex pattern did not match.
  Expected regex: 'Token exchange failed'
  Actual message: "unsupported operand type(s) for >>: 'float' and 'float'"
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 49 passed, 3 deselected, 1 warning in 2.26s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 2, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -249,7 +249,7 @@
                     event="APPROVE",
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="success").inc()
 
....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_success _____________________

self = <tests.test_github_client.TestApprovePR object at 0x7f278dea07d0>

    def test_approve_pr_success(self):
        """Test successful PR approval."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.approve_pr(123456, "owner/repo", 42)
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:313: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:27:56 [error    ] Failed to approve PR #42 in owner/repo: unsupported operand type(s) for >>: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for >>: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 52 passed, 3 deselected, 1 warning in 2.10s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 3, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -269,7 +269,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="failure").inc()
 
.....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_failure _____________________

self = <stampbot.github_client.GitHubAppClient object at 0x7fc4d26d6620>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
comment = 'Auto-approved by Stampbot'

    def approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str = "Auto-approved by Stampbot",
    ) -> bool:
        """Approve a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            comment: Review comment
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Create approval review
>               pr.create_review(
                    body=comment,
                    event="APPROVE",
                )

stampbot/github_client.py:247: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull().create_review' id='140483320842960'>
args = (), kwargs = {'body': 'Auto-approved by Stampbot', 'event': 'APPROVE'}
effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestApprovePR object at 0x7fc4d6898910>

    def test_approve_pr_failure(self):
        """Test PR approval failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_pr.create_review.side_effect = Exception("API Error")
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.approve_pr(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:350: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fc4d26d6620>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
comment = 'Auto-approved by Stampbot'

    def approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str = "Auto-approved by Stampbot",
    ) -> bool:
        """Approve a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            comment: Review comment
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Create approval review
                pr.create_review(
                    body=comment,
                    event="APPROVE",
                )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                github_api_requests_total.labels(operation="approve", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "approved"})
                set_span_ok(span)
    
                logger.info(
                    f"Approved PR #{pr_number} in {repo_full_name}",
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() >> start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/github_client.py:272: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_failure - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 53 passed, 3 deselected, 1 warning in 2.27s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 4, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -318,7 +318,7 @@
                 pr = repo.get_pull(pr_number)
                 head_sha: str = pr.head.sha
 
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="success").inc()
 
......................................................F
=================================== FAILURES ===================================
________________ TestGetPRHeadSHA.test_get_pr_head_sha_success _________________

self = <tests.test_github_client.TestGetPRHeadSHA object at 0x7ff623b58a50>

    def test_get_pr_head_sha_success(self):
        """Test successful PR head SHA lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_pr.head.sha = "current-head"
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_pr_head_sha(123456, "owner/repo", 42)
    
>           assert result == "current-head"
E           AssertionError: assert None == 'current-head'

tests/test_github_client.py:395: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:26:16 [error    ] Failed to get head SHA for PR #42 in owner/repo: unsupported operand type(s) for >>: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for >>: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetPRHeadSHA::test_get_pr_head_sha_success - AssertionError: assert None == 'current-head'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 54 passed, 3 deselected, 1 warning in 2.12s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 5, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -330,7 +330,7 @@
                 return head_sha
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="failure").inc()
 
.......................................................F
=================================== FAILURES ===================================
_________ TestGetPRHeadSHA.test_get_pr_head_sha_returns_none_on_error __________

self = <stampbot.github_client.GitHubAppClient object at 0x7f47e49a2530>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def get_pr_head_sha(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> str | None:
        """Get the current head SHA for a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Current pull request head SHA, or None on error.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_pr_head_sha",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:317: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='139946735930064'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetPRHeadSHA object at 0x7f47e7d60b90>

    def test_get_pr_head_sha_returns_none_on_error(self):
        """Test PR head SHA lookup returns None on API errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_pr_head_sha(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:427: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f47e49a2530>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def get_pr_head_sha(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> str | None:
        """Get the current head SHA for a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Current pull request head SHA, or None on error.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_pr_head_sha",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
                head_sha: str = pr.head.sha
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                github_api_requests_total.labels(operation="get_pull", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.head_sha": head_sha})
                set_span_ok(span)
    
                return head_sha
    
            except Exception as e:
>               duration = time.time() >> start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/github_client.py:333: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetPRHeadSHA::test_get_pr_head_sha_returns_none_on_error - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 55 passed, 3 deselected, 1 warning in 2.26s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 6, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -390,7 +390,7 @@
                 review = pr.get_review(review_id)
                 review.dismiss(message)
 
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="success").inc()
 
........................................................F
=================================== FAILURES ===================================
______________ TestDismissApproval.test_dismiss_approval_success _______________

self = <tests.test_github_client.TestDismissApproval object at 0x7fc8c37c8cd0>

    def test_dismiss_approval_success(self):
        """Test successful approval dismissal."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_review = Mock()
            mock_pr = Mock()
            mock_pr.get_review.return_value = mock_review
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.dismiss_approval(123456, "owner/repo", 42, 999)
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:473: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:26:46 [error    ] Failed to dismiss approval for PR #42 in owner/repo: unsupported operand type(s) for >>: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for >>: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestDismissApproval::test_dismiss_approval_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 56 passed, 3 deselected, 1 warning in 2.16s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 7, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -411,7 +411,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="failure").inc()
 
.........................................................F
=================================== FAILURES ===================================
______________ TestDismissApproval.test_dismiss_approval_failure _______________

self = <stampbot.github_client.GitHubAppClient object at 0x7f005c7bf9d0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
review_id = 999, message = 'Approval dismissed by Stampbot'

    def dismiss_approval(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        review_id: int,
        message: str = "Approval dismissed by Stampbot",
    ) -> bool:
        """Dismiss a pull request approval.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            review_id: Review ID to dismiss
            message: Dismissal message
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.dismiss_approval",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.review_id": review_id,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get the review and dismiss it
                review = pr.get_review(review_id)
>               review.dismiss(message)

stampbot/github_client.py:391: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull().get_review().dismiss' id='139639528595408'>
args = ('Approval dismissed by Stampbot',), kwargs = {}
effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestDismissApproval object at 0x7f0060a0ce10>

    def test_dismiss_approval_failure(self):
        """Test approval dismissal failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_review = Mock()
            mock_review.dismiss.side_effect = Exception("API Error")
            mock_pr = Mock()
            mock_pr.get_review.return_value = mock_review
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.dismiss_approval(123456, "owner/repo", 42, 999)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:512: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f005c7bf9d0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
review_id = 999, message = 'Approval dismissed by Stampbot'

    def dismiss_approval(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        review_id: int,
        message: str = "Approval dismissed by Stampbot",
    ) -> bool:
        """Dismiss a pull request approval.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            review_id: Review ID to dismiss
            message: Dismissal message
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.dismiss_approval",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.review_id": review_id,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get the review and dismiss it
                review = pr.get_review(review_id)
                review.dismiss(message)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                github_api_requests_total.labels(operation="dismiss", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "dismissed"})
                set_span_ok(span)
    
                logger.info(
                    f"Dismissed approval for PR #{pr_number} in {repo_full_name}",
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                        "review_id": review_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() >> start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/github_client.py:414: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestDismissApproval::test_dismiss_approval_failure - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 57 passed, 3 deselected, 1 warning in 2.25s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 8, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -466,7 +466,7 @@
 
                 content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                 if isinstance(content, list):
-                    duration = time.time() - start_time
+                    duration = time.time() >> start_time
                     github_api_request_duration_seconds.labels(operation="get_file").observe(
                         duration
                     )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 9, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -475,7 +475,7 @@
                     set_span_ok(span)
                     return None
 
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="success").inc()
 
..........................................................F
=================================== FAILURES ===================================
__________________ TestGetRepoFile.test_get_repo_file_success __________________

self = <tests.test_github_client.TestGetRepoFile object at 0x7f1e92864f50>

    def test_get_repo_file_success(self):
        """Test successful file retrieval."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_content = Mock()
            mock_content.decoded_content = b"file content"
            mock_repo = Mock()
            mock_repo.get_contents.return_value = mock_content
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_repo_file(123456, "owner/repo", "stampbot.toml")
    
>           assert result == "file content"
E           AssertionError: assert None == 'file content'

tests/test_github_client.py:557: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:42:34 [debug    ] Could not fetch stampbot.toml from owner/repo: unsupported operand type(s) for >>: 'float' and 'float' extra={'repo': 'owner/repo', 'file_path': 'stampbot.toml', 'installation_id': 123456}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetRepoFile::test_get_repo_file_success - AssertionError: assert None == 'file content'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 58 passed, 3 deselected, 1 warning in 2.12s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 10, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -487,7 +487,7 @@
                 return content.decoded_content.decode("utf-8")
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="not_found").inc()
 
............................................................F
=================================== FAILURES ===================================
___________ TestGetRepoFile.test_get_repo_file_returns_none_on_error ___________

self = <stampbot.github_client.GitHubAppClient object at 0x7f508af6e6d0>
installation_id = 123456, repo_full_name = 'owner/repo'
file_path = 'nonexistent.toml', ref = None

    def get_repo_file(
        self,
        installation_id: int,
        repo_full_name: str,
        file_path: str,
        ref: str | None = None,
    ) -> str | None:
        """Get file content from repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            file_path: Path to file in repository
            ref: Git reference (branch, tag, commit). Defaults to default branch
    
        Returns:
            File content as string, or None if not found
        """
        start_time = time.time()
    
        with create_span(
            "github.get_file",
            {
                "github.repo": repo_full_name,
                "github.file_path": file_path,
                "github.ref": ref or "default",
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
>               content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:467: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_contents' id='139983836107104'>
args = ('nonexistent.toml',), kwargs = {'ref': None}
effect = Exception('File not found')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: File not found

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetRepoFile object at 0x7f508af70770>

    def test_get_repo_file_returns_none_on_error(self):
        """Test that get_repo_file returns None when file not found."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_contents.side_effect = Exception("File not found")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_repo_file(123456, "owner/repo", "nonexistent.toml")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:628: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f508af6e6d0>
installation_id = 123456, repo_full_name = 'owner/repo'
file_path = 'nonexistent.toml', ref = None

    def get_repo_file(
        self,
        installation_id: int,
        repo_full_name: str,
        file_path: str,
        ref: str | None = None,
    ) -> str | None:
        """Get file content from repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            file_path: Path to file in repository
            ref: Git reference (branch, tag, commit). Defaults to default branch
    
        Returns:
            File content as string, or None if not found
        """
        start_time = time.time()
    
        with create_span(
            "github.get_file",
            {
                "github.repo": repo_full_name,
                "github.file_path": file_path,
                "github.ref": ref or "default",
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
                content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                if isinstance(content, list):
                    duration = time.time() - start_time
                    github_api_request_duration_seconds.labels(operation="get_file").observe(
                        duration
                    )
                    github_api_requests_total.labels(operation="get_file", status="not_found").inc()
                    add_span_attributes(span, {"github.result": "not_found"})
                    set_span_ok(span)
                    return None
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                github_api_requests_total.labels(operation="get_file", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "found"})
                set_span_ok(span)
    
                return content.decoded_content.decode("utf-8")
    
            except Exception as e:
>               duration = time.time() >> start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/github_client.py:490: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetRepoFile::test_get_repo_file_returns_none_on_error - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 60 passed, 3 deselected, 1 warning in 2.27s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 11, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -546,7 +546,7 @@
                     if review.user.login == bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7fa91e8111d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [] == [123]
E             
E             Right contains one more item: 123
E             
E             Full diff:
E             + []
E             - [
E             -     123,
E             - ]

tests/test_github_client.py:685: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:48:22 [error    ] Failed to find bot reviews for PR #42 in owner/repo: unsupported operand type(s) for >>: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for >>: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [] == [123]
  
  Right contains one more item: 123
  
  Full diff:
  + []
  - [
  -     123,
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 12, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -562,7 +562,7 @@
                 return bot_review_ids
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
..............................................................F
=================================== FAILURES ===================================
_______ TestFindBotReviews.test_find_bot_reviews_returns_empty_on_error ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f54682dfcb0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[int]:
        """Find all reviews created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            List of review IDs created by the bot
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:535: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140000499905408'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestFindBotReviews object at 0x7f546c441310>

    def test_find_bot_reviews_returns_empty_on_error(self):
        """Test that find_bot_reviews returns empty list on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.find_bot_reviews(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:717: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f54682dfcb0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[int]:
        """Find all reviews created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            List of review IDs created by the bot
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get bot user via JWT-authenticated integration (installation tokens
                # cannot call GET /user, which is restricted by GitHub Apps integration)
                app_info = self.integration.get_app()
                bot_user = f"{app_info.slug}[bot]"
    
                # Find all reviews by bot that are approvals
                bot_review_ids = []
                for review in pr.get_reviews():
                    if review.user.login == bot_user and review.state == "APPROVED":
                        bot_review_ids.append(review.id)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                    duration
                )
                github_api_requests_total.labels(operation="find_reviews", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span, {"github.reviews_found": len(bot_review_ids), "github.bot_user": bot_user}
                )
                set_span_ok(span)
    
                return bot_review_ids
    
            except Exception as e:
>               duration = time.time() >> start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/github_client.py:565: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_returns_empty_on_error - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 62 passed, 3 deselected, 1 warning in 2.29s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 13, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -634,7 +634,7 @@
                             }
                         )
 
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
...............................................................F
=================================== FAILURES ===================================
______ TestFindBotApprovalReviews.test_find_bot_approval_reviews_success _______

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7f69b6669450>

    def test_find_bot_approval_reviews_success(self):
        """Test successful bot approval review state lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            bot_approved_review = Mock()
            bot_approved_review.user.login = "stampbot[bot]"
            bot_approved_review.state = "APPROVED"
            bot_approved_review.id = 123
            bot_approved_review.commit_id = "headsha"
    
            bot_dismissed_review = Mock()
            bot_dismissed_review.user.login = "stampbot[bot]"
            bot_dismissed_review.state = "DISMISSED"
            bot_dismissed_review.id = 124
            bot_dismissed_review.commit_id = "oldsha"
    
            bot_commented_review = Mock()
            bot_commented_review.user.login = "stampbot[bot]"
            bot_commented_review.state = "COMMENTED"
            bot_commented_review.id = 125
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [
                bot_approved_review,
                bot_dismissed_review,
                bot_commented_review,
                other_review,
            ]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
    
>           assert result == [
                {"id": 123, "state": "APPROVED", "commit_id": "headsha"},
                {"id": 124, "state": "DISMISSED", "commit_id": "oldsha"},
            ]
E           AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
E             
E             Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
E             
E             Full diff:
E             + []
E             - [
E             -     {
E             -         'commit_id': 'headsha',
E             -         'id': 123,
E             -         'state': 'APPROVED',
E             -     },
E             -     {
E             -         'commit_id': 'oldsha',
E             -         'id': 124,
E             -         'state': 'DISMISSED',
E             -     },
E             - ]

tests/test_github_client.py:790: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:56:28 [error    ] Failed to find bot approval reviews for PR #42 in owner/repo: unsupported operand type(s) for >>: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for >>: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_success - AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
  
  Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
  
  Full diff:
  + []
  - [
  -     {
  -         'commit_id': 'headsha',
  -         'id': 123,
  -         'state': 'APPROVED',
  -     },
  -     {
  -         'commit_id': 'oldsha',
  -         'id': 124,
  -         'state': 'DISMISSED',
  -     },
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 63 passed, 3 deselected, 1 warning in 2.21s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 14, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -650,7 +650,7 @@
                 return bot_reviews
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
................................................................F
=================================== FAILURES ===================================
_ TestFindBotApprovalReviews.test_find_bot_approval_reviews_returns_empty_on_error _

self = <stampbot.github_client.GitHubAppClient object at 0x7f3c16257dd0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_approval_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[BotReview]:
        """Find approval review states created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Review state details for bot approval reviews.
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_approval_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:615: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='139896046374256'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7f3c1a611590>

    def test_find_bot_approval_reviews_returns_empty_on_error(self):
        """Test that find_bot_approval_reviews returns empty list on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:825: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f3c16257dd0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_approval_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[BotReview]:
        """Find approval review states created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Review state details for bot approval reviews.
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_approval_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get bot user via JWT-authenticated integration (installation tokens
                # cannot call GET /user, which is restricted by GitHub Apps integration)
                app_info = self.integration.get_app()
                bot_user = f"{app_info.slug}[bot]"
    
                bot_reviews: list[BotReview] = []
                for review in pr.get_reviews():
                    if review.user.login == bot_user and review.state in (
                        "APPROVED",
                        "DISMISSED",
                    ):
                        bot_reviews.append(
                            {
                                "id": review.id,
                                "state": review.state,
                                "commit_id": getattr(review, "commit_id", None),
                            }
                        )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                    duration
                )
                github_api_requests_total.labels(operation="find_reviews", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span, {"github.reviews_found": len(bot_reviews), "github.bot_user": bot_user}
                )
                set_span_ok(span)
    
                return bot_reviews
    
            except Exception as e:
>               duration = time.time() >> start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/github_client.py:653: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_returns_empty_on_error - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 64 passed, 3 deselected, 1 warning in 2.28s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 15, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -707,7 +707,7 @@
 
                 pr.create_review(body=message, event="COMMENT")
 
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="success").inc()
 
........................................................................ [ 30%]
......F
=================================== FAILURES ===================================
_______ TestCreatePrReviewComment.test_create_pr_review_comment_success ________

self = <tests.test_github_client.TestCreatePrReviewComment object at 0x7fe828395e50>

    def test_create_pr_review_comment_success(self):
        """Test successful review comment creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_pr_review_comment(
                123456,
                "owner/repo",
                42,
                "Config error",
            )
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:1398: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:20:31 [warning  ] Failed to post config error review for PR #42 in owner/repo: unsupported operand type(s) for >>: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for >>: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreatePrReviewComment::test_create_pr_review_comment_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 78 passed, 3 deselected, 1 warning in 2.19s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 16, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -729,7 +729,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="failure").inc()
 
........................................................................ [ 30%]
.......F
=================================== FAILURES ===================================
_______ TestCreatePrReviewComment.test_create_pr_review_comment_failure ________

self = <stampbot.github_client.GitHubAppClient object at 0x7fe92b10c4d0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
message = 'Config error'

    def create_pr_review_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
    ) -> bool:
        """Create a comment review on a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            message: Review comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_review_comment",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               pr = repo.get_pull(pr_number)
                     ^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:706: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull' id='140639427868528'>
args = (42,), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestCreatePrReviewComment object at 0x7fe92f54df90>

    def test_create_pr_review_comment_failure(self):
        """Test review comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_pull.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.create_pr_review_comment(
                123456,
                "owner/repo",
                42,
                "Config error",
            )

tests/test_github_client.py:1433: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fe92b10c4d0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
message = 'Config error'

    def create_pr_review_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
    ) -> bool:
        """Create a comment review on a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            message: Review comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_review_comment",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                pr.create_review(body=message, event="COMMENT")
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                github_api_requests_total.labels(operation="comment", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "commented"})
                set_span_ok(span)
    
                logger.info(
                    "Posted config error review on PR #%d in %s",
                    pr_number,
                    repo_full_name,
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() >> start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/github_client.py:732: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreatePrReviewComment::test_create_pr_review_comment_failure - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 79 passed, 3 deselected, 1 warning in 2.31s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 17, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -784,7 +784,7 @@
 
                 issue.create_comment(message)
 
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........F
=================================== FAILURES ===================================
___________ TestCreateIssueComment.test_create_issue_comment_success ___________

self = <tests.test_github_client.TestCreateIssueComment object at 0x7f9170ade0d0>

    def test_create_issue_comment_success(self):
        """Test successful issue comment creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_issue = Mock()
            mock_repo = Mock()
            mock_repo.get_issue.return_value = mock_issue
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_issue_comment(
                123456,
                "owner/repo",
                42,
                "Help text",
            )
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:1487: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:33:20 [warning  ] Failed to post issue comment on #42 in owner/repo: unsupported operand type(s) for >>: 'float' and 'float' extra={'repo': 'owner/repo', 'issue_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for >>: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreateIssueComment::test_create_issue_comment_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 80 passed, 3 deselected, 1 warning in 2.18s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 18, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -808,7 +808,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
.........F
=================================== FAILURES ===================================
___________ TestCreateIssueComment.test_create_issue_comment_failure ___________

self = <stampbot.github_client.GitHubAppClient object at 0x7fa55920e750>
installation_id = 123456, repo_full_name = 'owner/repo', issue_number = 42
message = 'Help text'

    def create_issue_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        issue_number: int,
        message: str,
    ) -> bool:
        """Create a comment on an issue or pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            issue_number: Issue or pull request number
            message: Comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_issue_comment",
            {
                "github.repo": repo_full_name,
                "github.issue_number": issue_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               issue = repo.get_issue(issue_number)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:783: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_issue' id='140348143528528'>
args = (42,), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestCreateIssueComment object at 0x7fa55dd72210>

    def test_create_issue_comment_failure(self):
        """Test issue comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_issue.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.create_issue_comment(
                123456,
                "owner/repo",
                42,
                "Help text",
            )

tests/test_github_client.py:1523: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fa55920e750>
installation_id = 123456, repo_full_name = 'owner/repo', issue_number = 42
message = 'Help text'

    def create_issue_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        issue_number: int,
        message: str,
    ) -> bool:
        """Create a comment on an issue or pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            issue_number: Issue or pull request number
            message: Comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_issue_comment",
            {
                "github.repo": repo_full_name,
                "github.issue_number": issue_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                issue = repo.get_issue(issue_number)
    
                issue.create_comment(message)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                    duration
                )
                github_api_requests_total.labels(operation="issue_comment", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "commented"})
                set_span_ok(span)
    
                logger.info(
                    "Posted issue comment on #%d in %s",
                    issue_number,
                    repo_full_name,
                    extra={
                        "repo": repo_full_name,
                        "issue_number": issue_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() >> start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/github_client.py:811: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreateIssueComment::test_create_issue_comment_failure - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 81 passed, 3 deselected, 1 warning in 2.33s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 19, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -861,7 +861,7 @@
                 repo = client.get_repo(repo_full_name)
                 repo.get_label(label_name)
 
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="success").inc()
 
........................................................................ [ 30%]
..F
=================================== FAILURES ===================================
__________________ TestRepoHasLabel.test_repo_has_label_true ___________________

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f8ba0da5bd0>

    def test_repo_has_label_true(self):
        """Test repo_has_label returns True when label exists."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.return_value = Mock()
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.repo_has_label(123456, "owner/repo", "autoapprove")
    
>           assert result is True
E           assert None is True

tests/test_github_client.py:1239: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:22:14 [debug    ] Could not verify label autoapprove in owner/repo: unsupported operand type(s) for >>: 'float' and 'float' extra={'repo': 'owner/repo', 'label': 'autoapprove', 'installation_id': 123456, 'error': "unsupported operand type(s) for >>: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_true - assert None is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 74 passed, 3 deselected, 1 warning in 2.18s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 20, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -872,7 +872,7 @@
                 return True
 
             except GithubException as e:
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
...F
=================================== FAILURES ===================================
________________ TestRepoHasLabel.test_repo_has_label_not_found ________________

self = <stampbot.github_client.GitHubAppClient object at 0x7f8e792eddf0>
installation_id = 123456, repo_full_name = 'owner/repo', label_name = 'missing'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               repo.get_label(label_name)

stampbot/github_client.py:862: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_label' id='140249894279152'>
args = ('missing',), kwargs = {}
effect = GithubException(404 {"message": "Not Found"})

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               github.GithubException.GithubException: 404 {"message": "Not Found"}

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: GithubException

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f8e7d60dd10>

    def test_repo_has_label_not_found(self):
        """Test repo_has_label returns False when label is missing."""
        from github.GithubException import GithubException
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = GithubException(404, {"message": "Not Found"}, None)
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.repo_has_label(123456, "owner/repo", "missing")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1275: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f8e792eddf0>
installation_id = 123456, repo_full_name = 'owner/repo', label_name = 'missing'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                repo.get_label(label_name)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.label_found": True})
                set_span_ok(span)
                return True
    
            except GithubException as e:
>               duration = time.time() >> start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/github_client.py:875: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_not_found - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 75 passed, 3 deselected, 1 warning in 2.31s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 21, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -897,7 +897,7 @@
                 return None
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
.....F
=================================== FAILURES ===================================
__________________ TestRepoHasLabel.test_repo_has_label_error __________________

self = <stampbot.github_client.GitHubAppClient object at 0x7efe7a3bbe90>
installation_id = 123456, repo_full_name = 'owner/repo'
label_name = 'autoapprove'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               repo.get_label(label_name)

stampbot/github_client.py:862: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_label' id='139631437013952'>
args = ('autoapprove',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestRepoHasLabel object at 0x7efe7e5cce90>

    def test_repo_has_label_error(self):
        """Test repo_has_label returns None on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.repo_has_label(123456, "owner/repo", "autoapprove")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1349: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7efe7a3bbe90>
installation_id = 123456, repo_full_name = 'owner/repo'
label_name = 'autoapprove'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                repo.get_label(label_name)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.label_found": True})
                set_span_ok(span)
                return True
    
            except GithubException as e:
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="failure").inc()
    
                if e.status == 404:
                    add_span_attributes(span, {"github.label_found": False})
                    set_span_ok(span)
                    return False
    
                set_span_error(span, e)
                logger.debug(
                    "Could not verify label %s in %s: %s",
                    label_name,
                    repo_full_name,
                    _sanitize_error(e),
                    extra={
                        "repo": repo_full_name,
                        "label": label_name,
                        "installation_id": installation_id,
                        "error": _sanitize_error(e),
                    },
                )
                return None
    
            except Exception as e:
>               duration = time.time() >> start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/github_client.py:900: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_error - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 77 passed, 3 deselected, 1 warning in 2.32s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 22, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -960,7 +960,7 @@
 
                 has_permission = permission_index >= required_index
 
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
.................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_true ______________

self = <tests.test_github_client.TestUserHasPermission object at 0x7f1090c116d0>

    def test_user_has_permission_true(self):
        """Test required permission satisfied returns True."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.return_value = "write"
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.user_has_permission(123456, "owner/repo", "alice", "write")
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:868: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:18:22 [warning  ] Failed to check collaborator permission for alice in owner/repo: unsupported operand type(s) for >>: 'float' and 'float' extra={'repo': 'owner/repo', 'username': 'alice', 'installation_id': 123456, 'error': "unsupported operand type(s) for >>: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_true - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 65 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 23, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -980,7 +980,7 @@
                 return has_permission
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
...................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_error _____________

self = <stampbot.github_client.GitHubAppClient object at 0x7fb0320385f0>
installation_id = 123456, repo_full_name = 'owner/repo', username = 'carol'
required_permission = 'maintain'

    def user_has_permission(
        self,
        installation_id: int,
        repo_full_name: str,
        username: str,
        required_permission: str,
    ) -> bool:
        """Check whether a user has required access to a repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            username: GitHub username to check
            required_permission: Minimum required repository permission
    
        Returns:
            True if user meets or exceeds required permission, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.get_collaborator_permission",
            {
                "github.repo": repo_full_name,
                "github.username": username,
                "github.required_permission": required_permission,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
>               permission = repo.get_collaborator_permission(username)
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:952: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_collaborator_permission' id='140394730086688'>
args = ('carol',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestUserHasPermission object at 0x7fb03623c8a0>

    def test_user_has_permission_error(self):
        """Test permission check returns False on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.user_has_permission(123456, "owner/repo", "carol", "maintain")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:939: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fb0320385f0>
installation_id = 123456, repo_full_name = 'owner/repo', username = 'carol'
required_permission = 'maintain'

    def user_has_permission(
        self,
        installation_id: int,
        repo_full_name: str,
        username: str,
        required_permission: str,
    ) -> bool:
        """Check whether a user has required access to a repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            username: GitHub username to check
            required_permission: Minimum required repository permission
    
        Returns:
            True if user meets or exceeds required permission, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.get_collaborator_permission",
            {
                "github.repo": repo_full_name,
                "github.username": username,
                "github.required_permission": required_permission,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
                permission = repo.get_collaborator_permission(username)
                permission_order = ["none", "read", "triage", "write", "maintain", "admin"]
                try:
                    permission_index = permission_order.index(permission)
                    required_index = permission_order.index(required_permission)
                except ValueError:
                    permission_index = -1
                    required_index = 99
    
                has_permission = permission_index >= required_index
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_permission").observe(
                    duration
                )
                github_api_requests_total.labels(operation="get_permission", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span,
                    {
                        "github.permission": permission,
                        "github.has_permission": has_permission,
                    },
                )
                set_span_ok(span)
    
                return has_permission
    
            except Exception as e:
>               duration = time.time() >> start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/github_client.py:983: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_error - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 67 passed, 3 deselected, 1 warning in 2.30s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 24, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1071,7 +1071,7 @@
                         )
                         continue
 
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
.....................................................................F
=================================== FAILURES ===================================
____________ TestGetUserTeamSlugs.test_get_user_team_slugs_success _____________

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7f9de4c39950>

    def test_get_user_team_slugs_success(self):
        """Test successful team membership check."""
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            # Mock user
            mock_user = Mock()
            mock_user.login = "alice"
    
            # Mock team that has alice as member
            mock_team = Mock()
            mock_team.has_in_members.return_value = True
    
            # Mock org
            mock_org = Mock()
            mock_org.get_team_by_slug.return_value = mock_team
    
            mock_github = Mock()
            mock_github.get_organization.return_value = mock_org
            mock_github.get_user.return_value = mock_user
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_user_team_slugs(
                123456, "acme", "alice", ["release-team", "deploy-team"]
            )
    
>           assert result == ["release-team", "deploy-team"]
E           AssertionError: assert [] == ['release-tea...'deploy-team']
E             
E             Right contains 2 more items, first extra item: 'release-team'
E             
E             Full diff:
E             + []
E             - [
E             -     'release-team',
E             -     'deploy-team',
E             - ]

tests/test_github_client.py:1033: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:49:44 [debug    ] User alice is a member of team release-team extra={'org': 'acme', 'username': 'alice', 'team': 'release-team'}
2026-06-29 05:49:44 [debug    ] User alice is a member of team deploy-team extra={'org': 'acme', 'username': 'alice', 'team': 'deploy-team'}
2026-06-29 05:49:44 [warning  ] Failed to check team memberships for alice in acme: unsupported operand type(s) for >>: 'float' and 'float' extra={'org': 'acme', 'username': 'alice', 'installation_id': 123456, 'error': "unsupported operand type(s) for >>: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_success - AssertionError: assert [] == ['release-tea...'deploy-team']
  
  Right contains 2 more items, first extra item: 'release-team'
  
  Full diff:
  + []
  - [
  -     'release-team',
  -     'deploy-team',
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 69 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 25, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1091,7 +1091,7 @@
                 return member_teams
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() >> start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
.F
=================================== FAILURES ===================================
_______ TestGetUserTeamSlugs.test_get_user_team_slugs_general_exception ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f8aefea8dd0>
installation_id = 123456, org_name = 'acme', username = 'alice'
allowed_teams = ['release-team']

    def get_user_team_slugs(
        self,
        installation_id: int,
        org_name: str,
        username: str,
        allowed_teams: list[str],
    ) -> list[str]:
        """Get team slugs the user is a member of from the allowed teams list.
    
        Args:
            installation_id: GitHub App installation ID
            org_name: Organization name
            username: GitHub username to check
            allowed_teams: List of team slugs to check (can be "org/team" or just "team")
    
        Returns:
            List of team slugs the user is a member of
        """
        start_time = time.time()
    
        with create_span(
            "github.get_user_team_slugs",
            {
                "github.org": org_name,
                "github.username": username,
                "github.installation_id": installation_id,
                "github.teams_to_check": len(allowed_teams),
            },
        ) as span:
            member_teams: list[str] = []
    
            try:
                client = self._get_installation_client(installation_id)
>               org = client.get_organization(org_name)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:1038: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_organization' id='140234706789312'>
args = ('acme',), kwargs = {}, effect = Exception('Network error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Network error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7f8af4497e30>

    def test_get_user_team_slugs_general_exception(self):
        """Test team membership check with general exception."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_organization.side_effect = Exception("Network error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_user_team_slugs(123456, "acme", "alice", ["release-team"])
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1195: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f8aefea8dd0>
installation_id = 123456, org_name = 'acme', username = 'alice'
allowed_teams = ['release-team']

    def get_user_team_slugs(
        self,
        installation_id: int,
        org_name: str,
        username: str,
        allowed_teams: list[str],
    ) -> list[str]:
        """Get team slugs the user is a member of from the allowed teams list.
    
        Args:
            installation_id: GitHub App installation ID
            org_name: Organization name
            username: GitHub username to check
            allowed_teams: List of team slugs to check (can be "org/team" or just "team")
    
        Returns:
            List of team slugs the user is a member of
        """
        start_time = time.time()
    
        with create_span(
            "github.get_user_team_slugs",
            {
                "github.org": org_name,
                "github.username": username,
                "github.installation_id": installation_id,
                "github.teams_to_check": len(allowed_teams),
            },
        ) as span:
            member_teams: list[str] = []
    
            try:
                client = self._get_installation_client(installation_id)
                org = client.get_organization(org_name)
    
                for team_ref in allowed_teams:
                    # Extract team slug (handle both "org/team" and "team" formats)
                    team_slug = team_ref.split("/")[-1] if "/" in team_ref else team_ref
    
                    try:
                        team = org.get_team_by_slug(team_slug)
                        # Check if user is a member
                        user = client.get_user(username)
                        if team.has_in_members(user):  # type: ignore[arg-type]
                            member_teams.append(team_slug)
                            logger.debug(
                                "User %s is a member of team %s",
                                username,
                                team_slug,
                                extra={
                                    "org": org_name,
                                    "username": username,
                                    "team": team_slug,
                                },
                            )
                    except GithubException as e:
                        # Team not found or no access - skip silently
                        logger.debug(
                            "Could not check team %s membership: %s",
                            team_slug,
                            e.data.get("message", str(e)) if hasattr(e, "data") else str(e),
                            extra={
                                "org": org_name,
                                "team": team_slug,
                                "username": username,
                            },
                        )
                        continue
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                    duration
                )
                github_api_requests_total.labels(operation="get_user_teams", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span,
                    {
                        "github.member_teams": len(member_teams),
                        "github.teams_checked": len(allowed_teams),
                    },
                )
                set_span_ok(span)
    
                return member_teams
    
            except Exception as e:
>               duration = time.time() >> start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/github_client.py:1094: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_general_exception - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 73 passed, 3 deselected, 1 warning in 2.32s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 0, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -177,7 +177,7 @@
                     retry=retry,
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="success").inc()
 
................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_success ________

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f8e793142d0>

    def test_get_installation_client_success(self):
        """Test successful installation client creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client._get_installation_client(123456)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:211: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f8e750c58d0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
                auth = self.integration.get_access_token(installation_id)
    
                # Configure retry with exponential backoff
                retry = Retry(
                    total=GITHUB_API_RETRY_TOTAL,
                    backoff_factor=GITHUB_API_RETRY_BACKOFF,
                    status_forcelist=[500, 502, 503, 504],
                    allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                )
    
                client = Github(
                    auth=Auth.Token(auth.token),
                    timeout=GITHUB_API_TIMEOUT,
                    retry=retry,
                )
    
>               duration = time.time() << start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/github_client.py:180: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_success - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 48 passed, 3 deselected, 1 warning in 2.16s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 1, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -185,7 +185,7 @@
                 return client
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="failure").inc()
                 set_span_error(span, e)
.................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_failure ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f03715776c0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
>               auth = self.integration.get_access_token(installation_id)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:164: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='GithubIntegration().get_access_token' id='139652717775232'>
args = (123456,), kwargs = {}, effect = Exception('Token exchange failed')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Token exchange failed

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f0372e1c410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            with pytest.raises(Exception, match="Token exchange failed"):
>               client._get_installation_client(123456)

tests/test_github_client.py:240: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f03715776c0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
                auth = self.integration.get_access_token(installation_id)
    
                # Configure retry with exponential backoff
                retry = Retry(
                    total=GITHUB_API_RETRY_TOTAL,
                    backoff_factor=GITHUB_API_RETRY_BACKOFF,
                    status_forcelist=[500, 502, 503, 504],
                    allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                )
    
                client = Github(
                    auth=Auth.Token(auth.token),
                    timeout=GITHUB_API_TIMEOUT,
                    retry=retry,
                )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                github_api_requests_total.labels(operation="get_token", status="success").inc()
    
                set_span_ok(span)
                return client
    
            except Exception as e:
>               duration = time.time() << start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/github_client.py:188: TypeError

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f0372e1c410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           with pytest.raises(Exception, match="Token exchange failed"):
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           AssertionError: Regex pattern did not match.
E             Expected regex: 'Token exchange failed'
E             Actual message: "unsupported operand type(s) for <<: 'float' and 'float'"

tests/test_github_client.py:239: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_failure - AssertionError: Regex pattern did not match.
  Expected regex: 'Token exchange failed'
  Actual message: "unsupported operand type(s) for <<: 'float' and 'float'"
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 49 passed, 3 deselected, 1 warning in 2.27s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 2, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -249,7 +249,7 @@
                     event="APPROVE",
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="success").inc()
 
....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_success _____________________

self = <tests.test_github_client.TestApprovePR object at 0x7f373d7c87d0>

    def test_approve_pr_success(self):
        """Test successful PR approval."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.approve_pr(123456, "owner/repo", 42)
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:313: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:25:02 [error    ] Failed to approve PR #42 in owner/repo: unsupported operand type(s) for <<: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for <<: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 52 passed, 3 deselected, 1 warning in 2.12s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 3, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -269,7 +269,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="failure").inc()
 
.....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_failure _____________________

self = <stampbot.github_client.GitHubAppClient object at 0x7f49eddda620>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
comment = 'Auto-approved by Stampbot'

    def approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str = "Auto-approved by Stampbot",
    ) -> bool:
        """Approve a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            comment: Review comment
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Create approval review
>               pr.create_review(
                    body=comment,
                    event="APPROVE",
                )

stampbot/github_client.py:247: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull().create_review' id='139955498126032'>
args = (), kwargs = {'body': 'Auto-approved by Stampbot', 'event': 'APPROVE'}
effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestApprovePR object at 0x7f49f1f58910>

    def test_approve_pr_failure(self):
        """Test PR approval failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_pr.create_review.side_effect = Exception("API Error")
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.approve_pr(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:350: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f49eddda620>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
comment = 'Auto-approved by Stampbot'

    def approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str = "Auto-approved by Stampbot",
    ) -> bool:
        """Approve a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            comment: Review comment
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Create approval review
                pr.create_review(
                    body=comment,
                    event="APPROVE",
                )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                github_api_requests_total.labels(operation="approve", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "approved"})
                set_span_ok(span)
    
                logger.info(
                    f"Approved PR #{pr_number} in {repo_full_name}",
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() << start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/github_client.py:272: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_failure - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 53 passed, 3 deselected, 1 warning in 2.27s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 4, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -318,7 +318,7 @@
                 pr = repo.get_pull(pr_number)
                 head_sha: str = pr.head.sha
 
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="success").inc()
 
......................................................F
=================================== FAILURES ===================================
________________ TestGetPRHeadSHA.test_get_pr_head_sha_success _________________

self = <tests.test_github_client.TestGetPRHeadSHA object at 0x7f678e8e0a50>

    def test_get_pr_head_sha_success(self):
        """Test successful PR head SHA lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_pr.head.sha = "current-head"
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_pr_head_sha(123456, "owner/repo", 42)
    
>           assert result == "current-head"
E           AssertionError: assert None == 'current-head'

tests/test_github_client.py:395: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:39:13 [error    ] Failed to get head SHA for PR #42 in owner/repo: unsupported operand type(s) for <<: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for <<: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetPRHeadSHA::test_get_pr_head_sha_success - AssertionError: assert None == 'current-head'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 54 passed, 3 deselected, 1 warning in 2.11s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 5, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -330,7 +330,7 @@
                 return head_sha
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="failure").inc()
 
.......................................................F
=================================== FAILURES ===================================
_________ TestGetPRHeadSHA.test_get_pr_head_sha_returns_none_on_error __________

self = <stampbot.github_client.GitHubAppClient object at 0x7f0a23fe6530>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def get_pr_head_sha(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> str | None:
        """Get the current head SHA for a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Current pull request head SHA, or None on error.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_pr_head_sha",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:317: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='139681511656144'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetPRHeadSHA object at 0x7f0a2745cb90>

    def test_get_pr_head_sha_returns_none_on_error(self):
        """Test PR head SHA lookup returns None on API errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_pr_head_sha(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:427: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f0a23fe6530>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def get_pr_head_sha(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> str | None:
        """Get the current head SHA for a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Current pull request head SHA, or None on error.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_pr_head_sha",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
                head_sha: str = pr.head.sha
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                github_api_requests_total.labels(operation="get_pull", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.head_sha": head_sha})
                set_span_ok(span)
    
                return head_sha
    
            except Exception as e:
>               duration = time.time() << start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/github_client.py:333: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetPRHeadSHA::test_get_pr_head_sha_returns_none_on_error - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 55 passed, 3 deselected, 1 warning in 2.25s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 6, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -390,7 +390,7 @@
                 review = pr.get_review(review_id)
                 review.dismiss(message)
 
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="success").inc()
 
........................................................F
=================================== FAILURES ===================================
______________ TestDismissApproval.test_dismiss_approval_success _______________

self = <tests.test_github_client.TestDismissApproval object at 0x7fe5143b8cd0>

    def test_dismiss_approval_success(self):
        """Test successful approval dismissal."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_review = Mock()
            mock_pr = Mock()
            mock_pr.get_review.return_value = mock_review
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.dismiss_approval(123456, "owner/repo", 42, 999)
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:473: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:41:35 [error    ] Failed to dismiss approval for PR #42 in owner/repo: unsupported operand type(s) for <<: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for <<: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestDismissApproval::test_dismiss_approval_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 56 passed, 3 deselected, 1 warning in 2.12s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 7, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -411,7 +411,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="failure").inc()
 
.........................................................F
=================================== FAILURES ===================================
______________ TestDismissApproval.test_dismiss_approval_failure _______________

self = <stampbot.github_client.GitHubAppClient object at 0x7f8f7afd7a50>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
review_id = 999, message = 'Approval dismissed by Stampbot'

    def dismiss_approval(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        review_id: int,
        message: str = "Approval dismissed by Stampbot",
    ) -> bool:
        """Dismiss a pull request approval.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            review_id: Review ID to dismiss
            message: Dismissal message
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.dismiss_approval",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.review_id": review_id,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get the review and dismiss it
                review = pr.get_review(review_id)
>               review.dismiss(message)

stampbot/github_client.py:391: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull().get_review().dismiss' id='140254218641360'>
args = ('Approval dismissed by Stampbot',), kwargs = {}
effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestDismissApproval object at 0x7f8f7f210e10>

    def test_dismiss_approval_failure(self):
        """Test approval dismissal failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_review = Mock()
            mock_review.dismiss.side_effect = Exception("API Error")
            mock_pr = Mock()
            mock_pr.get_review.return_value = mock_review
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.dismiss_approval(123456, "owner/repo", 42, 999)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:512: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f8f7afd7a50>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
review_id = 999, message = 'Approval dismissed by Stampbot'

    def dismiss_approval(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        review_id: int,
        message: str = "Approval dismissed by Stampbot",
    ) -> bool:
        """Dismiss a pull request approval.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            review_id: Review ID to dismiss
            message: Dismissal message
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.dismiss_approval",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.review_id": review_id,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get the review and dismiss it
                review = pr.get_review(review_id)
                review.dismiss(message)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                github_api_requests_total.labels(operation="dismiss", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "dismissed"})
                set_span_ok(span)
    
                logger.info(
                    f"Dismissed approval for PR #{pr_number} in {repo_full_name}",
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                        "review_id": review_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() << start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/github_client.py:414: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestDismissApproval::test_dismiss_approval_failure - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 57 passed, 3 deselected, 1 warning in 2.26s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 8, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -466,7 +466,7 @@
 
                 content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                 if isinstance(content, list):
-                    duration = time.time() - start_time
+                    duration = time.time() << start_time
                     github_api_request_duration_seconds.labels(operation="get_file").observe(
                         duration
                     )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 9, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -475,7 +475,7 @@
                     set_span_ok(span)
                     return None
 
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="success").inc()
 
..........................................................F
=================================== FAILURES ===================================
__________________ TestGetRepoFile.test_get_repo_file_success __________________

self = <tests.test_github_client.TestGetRepoFile object at 0x7fe3313ecf50>

    def test_get_repo_file_success(self):
        """Test successful file retrieval."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_content = Mock()
            mock_content.decoded_content = b"file content"
            mock_repo = Mock()
            mock_repo.get_contents.return_value = mock_content
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_repo_file(123456, "owner/repo", "stampbot.toml")
    
>           assert result == "file content"
E           AssertionError: assert None == 'file content'

tests/test_github_client.py:557: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:45:10 [debug    ] Could not fetch stampbot.toml from owner/repo: unsupported operand type(s) for <<: 'float' and 'float' extra={'repo': 'owner/repo', 'file_path': 'stampbot.toml', 'installation_id': 123456}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetRepoFile::test_get_repo_file_success - AssertionError: assert None == 'file content'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 58 passed, 3 deselected, 1 warning in 2.13s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 10, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -487,7 +487,7 @@
                 return content.decoded_content.decode("utf-8")
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="not_found").inc()
 
............................................................F
=================================== FAILURES ===================================
___________ TestGetRepoFile.test_get_repo_file_returns_none_on_error ___________

self = <stampbot.github_client.GitHubAppClient object at 0x7f879f9ea6d0>
installation_id = 123456, repo_full_name = 'owner/repo'
file_path = 'nonexistent.toml', ref = None

    def get_repo_file(
        self,
        installation_id: int,
        repo_full_name: str,
        file_path: str,
        ref: str | None = None,
    ) -> str | None:
        """Get file content from repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            file_path: Path to file in repository
            ref: Git reference (branch, tag, commit). Defaults to default branch
    
        Returns:
            File content as string, or None if not found
        """
        start_time = time.time()
    
        with create_span(
            "github.get_file",
            {
                "github.repo": repo_full_name,
                "github.file_path": file_path,
                "github.ref": ref or "default",
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
>               content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:467: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_contents' id='140220405977440'>
args = ('nonexistent.toml',), kwargs = {'ref': None}
effect = Exception('File not found')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: File not found

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetRepoFile object at 0x7f879f9ec770>

    def test_get_repo_file_returns_none_on_error(self):
        """Test that get_repo_file returns None when file not found."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_contents.side_effect = Exception("File not found")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_repo_file(123456, "owner/repo", "nonexistent.toml")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:628: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f879f9ea6d0>
installation_id = 123456, repo_full_name = 'owner/repo'
file_path = 'nonexistent.toml', ref = None

    def get_repo_file(
        self,
        installation_id: int,
        repo_full_name: str,
        file_path: str,
        ref: str | None = None,
    ) -> str | None:
        """Get file content from repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            file_path: Path to file in repository
            ref: Git reference (branch, tag, commit). Defaults to default branch
    
        Returns:
            File content as string, or None if not found
        """
        start_time = time.time()
    
        with create_span(
            "github.get_file",
            {
                "github.repo": repo_full_name,
                "github.file_path": file_path,
                "github.ref": ref or "default",
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
                content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                if isinstance(content, list):
                    duration = time.time() - start_time
                    github_api_request_duration_seconds.labels(operation="get_file").observe(
                        duration
                    )
                    github_api_requests_total.labels(operation="get_file", status="not_found").inc()
                    add_span_attributes(span, {"github.result": "not_found"})
                    set_span_ok(span)
                    return None
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                github_api_requests_total.labels(operation="get_file", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "found"})
                set_span_ok(span)
    
                return content.decoded_content.decode("utf-8")
    
            except Exception as e:
>               duration = time.time() << start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/github_client.py:490: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetRepoFile::test_get_repo_file_returns_none_on_error - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 60 passed, 3 deselected, 1 warning in 2.26s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 11, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -546,7 +546,7 @@
                     if review.user.login == bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7f395aca51d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [] == [123]
E             
E             Right contains one more item: 123
E             
E             Full diff:
E             + []
E             - [
E             -     123,
E             - ]

tests/test_github_client.py:685: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:56:18 [error    ] Failed to find bot reviews for PR #42 in owner/repo: unsupported operand type(s) for <<: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for <<: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [] == [123]
  
  Right contains one more item: 123
  
  Full diff:
  + []
  - [
  -     123,
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 12, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -562,7 +562,7 @@
                 return bot_review_ids
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
..............................................................F
=================================== FAILURES ===================================
_______ TestFindBotReviews.test_find_bot_reviews_returns_empty_on_error ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f51207dc2f0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[int]:
        """Find all reviews created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            List of review IDs created by the bot
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:535: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='139986412286848'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestFindBotReviews object at 0x7f5124959310>

    def test_find_bot_reviews_returns_empty_on_error(self):
        """Test that find_bot_reviews returns empty list on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.find_bot_reviews(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:717: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f51207dc2f0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[int]:
        """Find all reviews created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            List of review IDs created by the bot
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get bot user via JWT-authenticated integration (installation tokens
                # cannot call GET /user, which is restricted by GitHub Apps integration)
                app_info = self.integration.get_app()
                bot_user = f"{app_info.slug}[bot]"
    
                # Find all reviews by bot that are approvals
                bot_review_ids = []
                for review in pr.get_reviews():
                    if review.user.login == bot_user and review.state == "APPROVED":
                        bot_review_ids.append(review.id)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                    duration
                )
                github_api_requests_total.labels(operation="find_reviews", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span, {"github.reviews_found": len(bot_review_ids), "github.bot_user": bot_user}
                )
                set_span_ok(span)
    
                return bot_review_ids
    
            except Exception as e:
>               duration = time.time() << start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/github_client.py:565: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_returns_empty_on_error - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 62 passed, 3 deselected, 1 warning in 2.27s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 13, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -634,7 +634,7 @@
                             }
                         )
 
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
...............................................................F
=================================== FAILURES ===================================
______ TestFindBotApprovalReviews.test_find_bot_approval_reviews_success _______

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7fe187c0d450>

    def test_find_bot_approval_reviews_success(self):
        """Test successful bot approval review state lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            bot_approved_review = Mock()
            bot_approved_review.user.login = "stampbot[bot]"
            bot_approved_review.state = "APPROVED"
            bot_approved_review.id = 123
            bot_approved_review.commit_id = "headsha"
    
            bot_dismissed_review = Mock()
            bot_dismissed_review.user.login = "stampbot[bot]"
            bot_dismissed_review.state = "DISMISSED"
            bot_dismissed_review.id = 124
            bot_dismissed_review.commit_id = "oldsha"
    
            bot_commented_review = Mock()
            bot_commented_review.user.login = "stampbot[bot]"
            bot_commented_review.state = "COMMENTED"
            bot_commented_review.id = 125
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [
                bot_approved_review,
                bot_dismissed_review,
                bot_commented_review,
                other_review,
            ]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
    
>           assert result == [
                {"id": 123, "state": "APPROVED", "commit_id": "headsha"},
                {"id": 124, "state": "DISMISSED", "commit_id": "oldsha"},
            ]
E           AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
E             
E             Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
E             
E             Full diff:
E             + []
E             - [
E             -     {
E             -         'commit_id': 'headsha',
E             -         'id': 123,
E             -         'state': 'APPROVED',
E             -     },
E             -     {
E             -         'commit_id': 'oldsha',
E             -         'id': 124,
E             -         'state': 'DISMISSED',
E             -     },
E             - ]

tests/test_github_client.py:790: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:08:24 [error    ] Failed to find bot approval reviews for PR #42 in owner/repo: unsupported operand type(s) for <<: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for <<: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_success - AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
  
  Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
  
  Full diff:
  + []
  - [
  -     {
  -         'commit_id': 'headsha',
  -         'id': 123,
  -         'state': 'APPROVED',
  -     },
  -     {
  -         'commit_id': 'oldsha',
  -         'id': 124,
  -         'state': 'DISMISSED',
  -     },
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 63 passed, 3 deselected, 1 warning in 2.13s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 14, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -650,7 +650,7 @@
                 return bot_reviews
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
................................................................F
=================================== FAILURES ===================================
_ TestFindBotApprovalReviews.test_find_bot_approval_reviews_returns_empty_on_error _

self = <stampbot.github_client.GitHubAppClient object at 0x7fea505189b0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_approval_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[BotReview]:
        """Find approval review states created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Review state details for bot approval reviews.
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_approval_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:615: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140644346858864'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7fea54881590>

    def test_find_bot_approval_reviews_returns_empty_on_error(self):
        """Test that find_bot_approval_reviews returns empty list on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:825: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fea505189b0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_approval_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[BotReview]:
        """Find approval review states created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Review state details for bot approval reviews.
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_approval_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get bot user via JWT-authenticated integration (installation tokens
                # cannot call GET /user, which is restricted by GitHub Apps integration)
                app_info = self.integration.get_app()
                bot_user = f"{app_info.slug}[bot]"
    
                bot_reviews: list[BotReview] = []
                for review in pr.get_reviews():
                    if review.user.login == bot_user and review.state in (
                        "APPROVED",
                        "DISMISSED",
                    ):
                        bot_reviews.append(
                            {
                                "id": review.id,
                                "state": review.state,
                                "commit_id": getattr(review, "commit_id", None),
                            }
                        )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                    duration
                )
                github_api_requests_total.labels(operation="find_reviews", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span, {"github.reviews_found": len(bot_reviews), "github.bot_user": bot_user}
                )
                set_span_ok(span)
    
                return bot_reviews
    
            except Exception as e:
>               duration = time.time() << start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/github_client.py:653: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_returns_empty_on_error - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 64 passed, 3 deselected, 1 warning in 2.31s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 15, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -707,7 +707,7 @@
 
                 pr.create_review(body=message, event="COMMENT")
 
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="success").inc()
 
........................................................................ [ 30%]
......F
=================================== FAILURES ===================================
_______ TestCreatePrReviewComment.test_create_pr_review_comment_success ________

self = <tests.test_github_client.TestCreatePrReviewComment object at 0x7f8251071e50>

    def test_create_pr_review_comment_success(self):
        """Test successful review comment creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_pr_review_comment(
                123456,
                "owner/repo",
                42,
                "Config error",
            )
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:1398: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:32:49 [warning  ] Failed to post config error review for PR #42 in owner/repo: unsupported operand type(s) for <<: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for <<: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreatePrReviewComment::test_create_pr_review_comment_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 78 passed, 3 deselected, 1 warning in 2.20s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 16, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -729,7 +729,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="failure").inc()
 
........................................................................ [ 30%]
.......F
=================================== FAILURES ===================================
_______ TestCreatePrReviewComment.test_create_pr_review_comment_failure ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f07cc5dc230>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
message = 'Config error'

    def create_pr_review_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
    ) -> bool:
        """Create a comment review on a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            message: Review comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_review_comment",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               pr = repo.get_pull(pr_number)
                     ^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:706: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull' id='139671471339376'>
args = (42,), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestCreatePrReviewComment object at 0x7f07d0911f90>

    def test_create_pr_review_comment_failure(self):
        """Test review comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_pull.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.create_pr_review_comment(
                123456,
                "owner/repo",
                42,
                "Config error",
            )

tests/test_github_client.py:1433: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f07cc5dc230>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
message = 'Config error'

    def create_pr_review_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
    ) -> bool:
        """Create a comment review on a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            message: Review comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_review_comment",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                pr.create_review(body=message, event="COMMENT")
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                github_api_requests_total.labels(operation="comment", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "commented"})
                set_span_ok(span)
    
                logger.info(
                    "Posted config error review on PR #%d in %s",
                    pr_number,
                    repo_full_name,
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() << start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/github_client.py:732: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreatePrReviewComment::test_create_pr_review_comment_failure - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 79 passed, 3 deselected, 1 warning in 2.32s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 17, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -784,7 +784,7 @@
 
                 issue.create_comment(message)
 
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........F
=================================== FAILURES ===================================
___________ TestCreateIssueComment.test_create_issue_comment_success ___________

self = <tests.test_github_client.TestCreateIssueComment object at 0x7fbe4e44a0d0>

    def test_create_issue_comment_success(self):
        """Test successful issue comment creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_issue = Mock()
            mock_repo = Mock()
            mock_repo.get_issue.return_value = mock_issue
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_issue_comment(
                123456,
                "owner/repo",
                42,
                "Help text",
            )
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:1487: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:53:27 [warning  ] Failed to post issue comment on #42 in owner/repo: unsupported operand type(s) for <<: 'float' and 'float' extra={'repo': 'owner/repo', 'issue_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for <<: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreateIssueComment::test_create_issue_comment_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 80 passed, 3 deselected, 1 warning in 2.18s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 18, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -808,7 +808,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
.........F
=================================== FAILURES ===================================
___________ TestCreateIssueComment.test_create_issue_comment_failure ___________

self = <stampbot.github_client.GitHubAppClient object at 0x7f7471f116d0>
installation_id = 123456, repo_full_name = 'owner/repo', issue_number = 42
message = 'Help text'

    def create_issue_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        issue_number: int,
        message: str,
    ) -> bool:
        """Create a comment on an issue or pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            issue_number: Issue or pull request number
            message: Comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_issue_comment",
            {
                "github.repo": repo_full_name,
                "github.issue_number": issue_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               issue = repo.get_issue(issue_number)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:783: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_issue' id='140138106448464'>
args = (42,), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestCreateIssueComment object at 0x7f7476382210>

    def test_create_issue_comment_failure(self):
        """Test issue comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_issue.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.create_issue_comment(
                123456,
                "owner/repo",
                42,
                "Help text",
            )

tests/test_github_client.py:1523: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f7471f116d0>
installation_id = 123456, repo_full_name = 'owner/repo', issue_number = 42
message = 'Help text'

    def create_issue_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        issue_number: int,
        message: str,
    ) -> bool:
        """Create a comment on an issue or pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            issue_number: Issue or pull request number
            message: Comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_issue_comment",
            {
                "github.repo": repo_full_name,
                "github.issue_number": issue_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                issue = repo.get_issue(issue_number)
    
                issue.create_comment(message)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                    duration
                )
                github_api_requests_total.labels(operation="issue_comment", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "commented"})
                set_span_ok(span)
    
                logger.info(
                    "Posted issue comment on #%d in %s",
                    issue_number,
                    repo_full_name,
                    extra={
                        "repo": repo_full_name,
                        "issue_number": issue_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() << start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/github_client.py:811: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreateIssueComment::test_create_issue_comment_failure - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 81 passed, 3 deselected, 1 warning in 2.32s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 19, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -861,7 +861,7 @@
                 repo = client.get_repo(repo_full_name)
                 repo.get_label(label_name)
 
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="success").inc()
 
........................................................................ [ 30%]
..F
=================================== FAILURES ===================================
__________________ TestRepoHasLabel.test_repo_has_label_true ___________________

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f3417e15bd0>

    def test_repo_has_label_true(self):
        """Test repo_has_label returns True when label exists."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.return_value = Mock()
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.repo_has_label(123456, "owner/repo", "autoapprove")
    
>           assert result is True
E           assert None is True

tests/test_github_client.py:1239: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:16:08 [debug    ] Could not verify label autoapprove in owner/repo: unsupported operand type(s) for <<: 'float' and 'float' extra={'repo': 'owner/repo', 'label': 'autoapprove', 'installation_id': 123456, 'error': "unsupported operand type(s) for <<: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_true - assert None is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 74 passed, 3 deselected, 1 warning in 2.18s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 20, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -872,7 +872,7 @@
                 return True
 
             except GithubException as e:
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
...F
=================================== FAILURES ===================================
________________ TestRepoHasLabel.test_repo_has_label_not_found ________________

self = <stampbot.github_client.GitHubAppClient object at 0x7fc1df91a150>
installation_id = 123456, repo_full_name = 'owner/repo', label_name = 'missing'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               repo.get_label(label_name)

stampbot/github_client.py:862: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_label' id='140470657472496'>
args = ('missing',), kwargs = {}
effect = GithubException(404 {"message": "Not Found"})

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               github.GithubException.GithubException: 404 {"message": "Not Found"}

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: GithubException

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestRepoHasLabel object at 0x7fc1e4215d10>

    def test_repo_has_label_not_found(self):
        """Test repo_has_label returns False when label is missing."""
        from github.GithubException import GithubException
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = GithubException(404, {"message": "Not Found"}, None)
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.repo_has_label(123456, "owner/repo", "missing")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1275: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fc1df91a150>
installation_id = 123456, repo_full_name = 'owner/repo', label_name = 'missing'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                repo.get_label(label_name)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.label_found": True})
                set_span_ok(span)
                return True
    
            except GithubException as e:
>               duration = time.time() << start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/github_client.py:875: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_not_found - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 75 passed, 3 deselected, 1 warning in 2.31s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 21, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -897,7 +897,7 @@
                 return None
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
.....F
=================================== FAILURES ===================================
__________________ TestRepoHasLabel.test_repo_has_label_error __________________

self = <stampbot.github_client.GitHubAppClient object at 0x7f3d2a2c9a90>
installation_id = 123456, repo_full_name = 'owner/repo'
label_name = 'autoapprove'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               repo.get_label(label_name)

stampbot/github_client.py:862: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_label' id='139900676744128'>
args = ('autoapprove',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f3d2e474e90>

    def test_repo_has_label_error(self):
        """Test repo_has_label returns None on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.repo_has_label(123456, "owner/repo", "autoapprove")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1349: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f3d2a2c9a90>
installation_id = 123456, repo_full_name = 'owner/repo'
label_name = 'autoapprove'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                repo.get_label(label_name)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.label_found": True})
                set_span_ok(span)
                return True
    
            except GithubException as e:
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="failure").inc()
    
                if e.status == 404:
                    add_span_attributes(span, {"github.label_found": False})
                    set_span_ok(span)
                    return False
    
                set_span_error(span, e)
                logger.debug(
                    "Could not verify label %s in %s: %s",
                    label_name,
                    repo_full_name,
                    _sanitize_error(e),
                    extra={
                        "repo": repo_full_name,
                        "label": label_name,
                        "installation_id": installation_id,
                        "error": _sanitize_error(e),
                    },
                )
                return None
    
            except Exception as e:
>               duration = time.time() << start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/github_client.py:900: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_error - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 77 passed, 3 deselected, 1 warning in 2.31s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 22, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -960,7 +960,7 @@
 
                 has_permission = permission_index >= required_index
 
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
.................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_true ______________

self = <tests.test_github_client.TestUserHasPermission object at 0x7f22a87bd6d0>

    def test_user_has_permission_true(self):
        """Test required permission satisfied returns True."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.return_value = "write"
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.user_has_permission(123456, "owner/repo", "alice", "write")
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:868: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:39:46 [warning  ] Failed to check collaborator permission for alice in owner/repo: unsupported operand type(s) for <<: 'float' and 'float' extra={'repo': 'owner/repo', 'username': 'alice', 'installation_id': 123456, 'error': "unsupported operand type(s) for <<: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_true - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 65 passed, 3 deselected, 1 warning in 2.16s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 23, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -980,7 +980,7 @@
                 return has_permission
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
...................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_error _____________

self = <stampbot.github_client.GitHubAppClient object at 0x7f15fa438950>
installation_id = 123456, repo_full_name = 'owner/repo', username = 'carol'
required_permission = 'maintain'

    def user_has_permission(
        self,
        installation_id: int,
        repo_full_name: str,
        username: str,
        required_permission: str,
    ) -> bool:
        """Check whether a user has required access to a repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            username: GitHub username to check
            required_permission: Minimum required repository permission
    
        Returns:
            True if user meets or exceeds required permission, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.get_collaborator_permission",
            {
                "github.repo": repo_full_name,
                "github.username": username,
                "github.required_permission": required_permission,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
>               permission = repo.get_collaborator_permission(username)
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:952: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_collaborator_permission' id='139732369793312'>
args = ('carol',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestUserHasPermission object at 0x7f15fe6748a0>

    def test_user_has_permission_error(self):
        """Test permission check returns False on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.user_has_permission(123456, "owner/repo", "carol", "maintain")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:939: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f15fa438950>
installation_id = 123456, repo_full_name = 'owner/repo', username = 'carol'
required_permission = 'maintain'

    def user_has_permission(
        self,
        installation_id: int,
        repo_full_name: str,
        username: str,
        required_permission: str,
    ) -> bool:
        """Check whether a user has required access to a repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            username: GitHub username to check
            required_permission: Minimum required repository permission
    
        Returns:
            True if user meets or exceeds required permission, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.get_collaborator_permission",
            {
                "github.repo": repo_full_name,
                "github.username": username,
                "github.required_permission": required_permission,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
                permission = repo.get_collaborator_permission(username)
                permission_order = ["none", "read", "triage", "write", "maintain", "admin"]
                try:
                    permission_index = permission_order.index(permission)
                    required_index = permission_order.index(required_permission)
                except ValueError:
                    permission_index = -1
                    required_index = 99
    
                has_permission = permission_index >= required_index
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_permission").observe(
                    duration
                )
                github_api_requests_total.labels(operation="get_permission", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span,
                    {
                        "github.permission": permission,
                        "github.has_permission": has_permission,
                    },
                )
                set_span_ok(span)
    
                return has_permission
    
            except Exception as e:
>               duration = time.time() << start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/github_client.py:983: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_error - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 67 passed, 3 deselected, 1 warning in 2.28s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 24, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1071,7 +1071,7 @@
                         )
                         continue
 
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
.....................................................................F
=================================== FAILURES ===================================
____________ TestGetUserTeamSlugs.test_get_user_team_slugs_success _____________

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7ffbd5bc1950>

    def test_get_user_team_slugs_success(self):
        """Test successful team membership check."""
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            # Mock user
            mock_user = Mock()
            mock_user.login = "alice"
    
            # Mock team that has alice as member
            mock_team = Mock()
            mock_team.has_in_members.return_value = True
    
            # Mock org
            mock_org = Mock()
            mock_org.get_team_by_slug.return_value = mock_team
    
            mock_github = Mock()
            mock_github.get_organization.return_value = mock_org
            mock_github.get_user.return_value = mock_user
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_user_team_slugs(
                123456, "acme", "alice", ["release-team", "deploy-team"]
            )
    
>           assert result == ["release-team", "deploy-team"]
E           AssertionError: assert [] == ['release-tea...'deploy-team']
E             
E             Right contains 2 more items, first extra item: 'release-team'
E             
E             Full diff:
E             + []
E             - [
E             -     'release-team',
E             -     'deploy-team',
E             - ]

tests/test_github_client.py:1033: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:43:20 [debug    ] User alice is a member of team release-team extra={'org': 'acme', 'username': 'alice', 'team': 'release-team'}
2026-06-29 04:43:20 [debug    ] User alice is a member of team deploy-team extra={'org': 'acme', 'username': 'alice', 'team': 'deploy-team'}
2026-06-29 04:43:20 [warning  ] Failed to check team memberships for alice in acme: unsupported operand type(s) for <<: 'float' and 'float' extra={'org': 'acme', 'username': 'alice', 'installation_id': 123456, 'error': "unsupported operand type(s) for <<: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_success - AssertionError: assert [] == ['release-tea...'deploy-team']
  
  Right contains 2 more items, first extra item: 'release-team'
  
  Full diff:
  + []
  - [
  -     'release-team',
  -     'deploy-team',
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 69 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 25, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1091,7 +1091,7 @@
                 return member_teams
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() << start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
.F
=================================== FAILURES ===================================
_______ TestGetUserTeamSlugs.test_get_user_team_slugs_general_exception ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f04bf6cf7d0>
installation_id = 123456, org_name = 'acme', username = 'alice'
allowed_teams = ['release-team']

    def get_user_team_slugs(
        self,
        installation_id: int,
        org_name: str,
        username: str,
        allowed_teams: list[str],
    ) -> list[str]:
        """Get team slugs the user is a member of from the allowed teams list.
    
        Args:
            installation_id: GitHub App installation ID
            org_name: Organization name
            username: GitHub username to check
            allowed_teams: List of team slugs to check (can be "org/team" or just "team")
    
        Returns:
            List of team slugs the user is a member of
        """
        start_time = time.time()
    
        with create_span(
            "github.get_user_team_slugs",
            {
                "github.org": org_name,
                "github.username": username,
                "github.installation_id": installation_id,
                "github.teams_to_check": len(allowed_teams),
            },
        ) as span:
            member_teams: list[str] = []
    
            try:
                client = self._get_installation_client(installation_id)
>               org = client.get_organization(org_name)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:1038: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_organization' id='139658367607744'>
args = ('acme',), kwargs = {}, effect = Exception('Network error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Network error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7f04c3e77e30>

    def test_get_user_team_slugs_general_exception(self):
        """Test team membership check with general exception."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_organization.side_effect = Exception("Network error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_user_team_slugs(123456, "acme", "alice", ["release-team"])
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1195: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f04bf6cf7d0>
installation_id = 123456, org_name = 'acme', username = 'alice'
allowed_teams = ['release-team']

    def get_user_team_slugs(
        self,
        installation_id: int,
        org_name: str,
        username: str,
        allowed_teams: list[str],
    ) -> list[str]:
        """Get team slugs the user is a member of from the allowed teams list.
    
        Args:
            installation_id: GitHub App installation ID
            org_name: Organization name
            username: GitHub username to check
            allowed_teams: List of team slugs to check (can be "org/team" or just "team")
    
        Returns:
            List of team slugs the user is a member of
        """
        start_time = time.time()
    
        with create_span(
            "github.get_user_team_slugs",
            {
                "github.org": org_name,
                "github.username": username,
                "github.installation_id": installation_id,
                "github.teams_to_check": len(allowed_teams),
            },
        ) as span:
            member_teams: list[str] = []
    
            try:
                client = self._get_installation_client(installation_id)
                org = client.get_organization(org_name)
    
                for team_ref in allowed_teams:
                    # Extract team slug (handle both "org/team" and "team" formats)
                    team_slug = team_ref.split("/")[-1] if "/" in team_ref else team_ref
    
                    try:
                        team = org.get_team_by_slug(team_slug)
                        # Check if user is a member
                        user = client.get_user(username)
                        if team.has_in_members(user):  # type: ignore[arg-type]
                            member_teams.append(team_slug)
                            logger.debug(
                                "User %s is a member of team %s",
                                username,
                                team_slug,
                                extra={
                                    "org": org_name,
                                    "username": username,
                                    "team": team_slug,
                                },
                            )
                    except GithubException as e:
                        # Team not found or no access - skip silently
                        logger.debug(
                            "Could not check team %s membership: %s",
                            team_slug,
                            e.data.get("message", str(e)) if hasattr(e, "data") else str(e),
                            extra={
                                "org": org_name,
                                "team": team_slug,
                                "username": username,
                            },
                        )
                        continue
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                    duration
                )
                github_api_requests_total.labels(operation="get_user_teams", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span,
                    {
                        "github.member_teams": len(member_teams),
                        "github.teams_checked": len(allowed_teams),
                    },
                )
                set_span_ok(span)
    
                return member_teams
    
            except Exception as e:
>               duration = time.time() << start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/github_client.py:1094: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_general_exception - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 73 passed, 3 deselected, 1 warning in 2.32s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 0, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -177,7 +177,7 @@
                     retry=retry,
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="success").inc()
 
................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_success ________

self = <tests.test_github_client.TestGetInstallationClient object at 0x7fa7abfa82d0>

    def test_get_installation_client_success(self):
        """Test successful installation client creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client._get_installation_client(123456)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:211: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fa7a7dc98d0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
                auth = self.integration.get_access_token(installation_id)
    
                # Configure retry with exponential backoff
                retry = Retry(
                    total=GITHUB_API_RETRY_TOTAL,
                    backoff_factor=GITHUB_API_RETRY_BACKOFF,
                    status_forcelist=[500, 502, 503, 504],
                    allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                )
    
                client = Github(
                    auth=Auth.Token(auth.token),
                    timeout=GITHUB_API_TIMEOUT,
                    retry=retry,
                )
    
>               duration = time.time() | start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/github_client.py:180: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_success - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 48 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 1, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -185,7 +185,7 @@
                 return client
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="failure").inc()
                 set_span_error(span, e)
.................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_failure ________

self = <stampbot.github_client.GitHubAppClient object at 0x7fd22ac776c0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
>               auth = self.integration.get_access_token(installation_id)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:164: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='GithubIntegration().get_access_token' id='140540592130432'>
args = (123456,), kwargs = {}, effect = Exception('Token exchange failed')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Token exchange failed

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7fd22c524410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            with pytest.raises(Exception, match="Token exchange failed"):
>               client._get_installation_client(123456)

tests/test_github_client.py:240: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fd22ac776c0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
                auth = self.integration.get_access_token(installation_id)
    
                # Configure retry with exponential backoff
                retry = Retry(
                    total=GITHUB_API_RETRY_TOTAL,
                    backoff_factor=GITHUB_API_RETRY_BACKOFF,
                    status_forcelist=[500, 502, 503, 504],
                    allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                )
    
                client = Github(
                    auth=Auth.Token(auth.token),
                    timeout=GITHUB_API_TIMEOUT,
                    retry=retry,
                )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                github_api_requests_total.labels(operation="get_token", status="success").inc()
    
                set_span_ok(span)
                return client
    
            except Exception as e:
>               duration = time.time() | start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/github_client.py:188: TypeError

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7fd22c524410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           with pytest.raises(Exception, match="Token exchange failed"):
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           AssertionError: Regex pattern did not match.
E             Expected regex: 'Token exchange failed'
E             Actual message: "unsupported operand type(s) for |: 'float' and 'float'"

tests/test_github_client.py:239: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_failure - AssertionError: Regex pattern did not match.
  Expected regex: 'Token exchange failed'
  Actual message: "unsupported operand type(s) for |: 'float' and 'float'"
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 49 passed, 3 deselected, 1 warning in 2.26s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 2, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -249,7 +249,7 @@
                     event="APPROVE",
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="success").inc()
 
....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_success _____________________

self = <tests.test_github_client.TestApprovePR object at 0x7fea6a5bc7d0>

    def test_approve_pr_success(self):
        """Test successful PR approval."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.approve_pr(123456, "owner/repo", 42)
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:313: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:13:59 [error    ] Failed to approve PR #42 in owner/repo: unsupported operand type(s) for |: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for |: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 52 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 3, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -269,7 +269,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="failure").inc()
 
.....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_failure _____________________

self = <stampbot.github_client.GitHubAppClient object at 0x7f91899fe620>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
comment = 'Auto-approved by Stampbot'

    def approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str = "Auto-approved by Stampbot",
    ) -> bool:
        """Approve a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            comment: Review comment
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Create approval review
>               pr.create_review(
                    body=comment,
                    event="APPROVE",
                )

stampbot/github_client.py:247: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull().create_review' id='140263056083664'>
args = (), kwargs = {'body': 'Auto-approved by Stampbot', 'event': 'APPROVE'}
effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestApprovePR object at 0x7f918dfbc910>

    def test_approve_pr_failure(self):
        """Test PR approval failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_pr.create_review.side_effect = Exception("API Error")
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.approve_pr(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:350: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f91899fe620>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
comment = 'Auto-approved by Stampbot'

    def approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str = "Auto-approved by Stampbot",
    ) -> bool:
        """Approve a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            comment: Review comment
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Create approval review
                pr.create_review(
                    body=comment,
                    event="APPROVE",
                )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                github_api_requests_total.labels(operation="approve", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "approved"})
                set_span_ok(span)
    
                logger.info(
                    f"Approved PR #{pr_number} in {repo_full_name}",
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() | start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/github_client.py:272: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_failure - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 53 passed, 3 deselected, 1 warning in 2.27s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 4, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -318,7 +318,7 @@
                 pr = repo.get_pull(pr_number)
                 head_sha: str = pr.head.sha
 
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="success").inc()
 
......................................................F
=================================== FAILURES ===================================
________________ TestGetPRHeadSHA.test_get_pr_head_sha_success _________________

self = <tests.test_github_client.TestGetPRHeadSHA object at 0x7fde27e4ca50>

    def test_get_pr_head_sha_success(self):
        """Test successful PR head SHA lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_pr.head.sha = "current-head"
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_pr_head_sha(123456, "owner/repo", 42)
    
>           assert result == "current-head"
E           AssertionError: assert None == 'current-head'

tests/test_github_client.py:395: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:32:32 [error    ] Failed to get head SHA for PR #42 in owner/repo: unsupported operand type(s) for |: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for |: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetPRHeadSHA::test_get_pr_head_sha_success - AssertionError: assert None == 'current-head'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 54 passed, 3 deselected, 1 warning in 2.11s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 5, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -330,7 +330,7 @@
                 return head_sha
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="failure").inc()
 
.......................................................F
=================================== FAILURES ===================================
_________ TestGetPRHeadSHA.test_get_pr_head_sha_returns_none_on_error __________

self = <stampbot.github_client.GitHubAppClient object at 0x7fc733dea530>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def get_pr_head_sha(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> str | None:
        """Get the current head SHA for a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Current pull request head SHA, or None on error.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_pr_head_sha",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:317: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140493526829776'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetPRHeadSHA object at 0x7fc736fb4b90>

    def test_get_pr_head_sha_returns_none_on_error(self):
        """Test PR head SHA lookup returns None on API errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_pr_head_sha(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:427: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fc733dea530>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def get_pr_head_sha(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> str | None:
        """Get the current head SHA for a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Current pull request head SHA, or None on error.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_pr_head_sha",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
                head_sha: str = pr.head.sha
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                github_api_requests_total.labels(operation="get_pull", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.head_sha": head_sha})
                set_span_ok(span)
    
                return head_sha
    
            except Exception as e:
>               duration = time.time() | start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/github_client.py:333: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetPRHeadSHA::test_get_pr_head_sha_returns_none_on_error - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 55 passed, 3 deselected, 1 warning in 2.25s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 6, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -390,7 +390,7 @@
                 review = pr.get_review(review_id)
                 review.dismiss(message)
 
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="success").inc()
 
........................................................F
=================================== FAILURES ===================================
______________ TestDismissApproval.test_dismiss_approval_success _______________

self = <tests.test_github_client.TestDismissApproval object at 0x7fb1198c8cd0>

    def test_dismiss_approval_success(self):
        """Test successful approval dismissal."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_review = Mock()
            mock_pr = Mock()
            mock_pr.get_review.return_value = mock_review
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.dismiss_approval(123456, "owner/repo", 42, 999)
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:473: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:33:05 [error    ] Failed to dismiss approval for PR #42 in owner/repo: unsupported operand type(s) for |: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for |: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestDismissApproval::test_dismiss_approval_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 56 passed, 3 deselected, 1 warning in 2.11s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 7, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -411,7 +411,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="failure").inc()
 
.........................................................F
=================================== FAILURES ===================================
______________ TestDismissApproval.test_dismiss_approval_failure _______________

self = <stampbot.github_client.GitHubAppClient object at 0x7fe93b1b39d0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
review_id = 999, message = 'Approval dismissed by Stampbot'

    def dismiss_approval(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        review_id: int,
        message: str = "Approval dismissed by Stampbot",
    ) -> bool:
        """Dismiss a pull request approval.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            review_id: Review ID to dismiss
            message: Dismissal message
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.dismiss_approval",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.review_id": review_id,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get the review and dismiss it
                review = pr.get_review(review_id)
>               review.dismiss(message)

stampbot/github_client.py:391: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull().get_review().dismiss' id='140639695986640'>
args = ('Approval dismissed by Stampbot',), kwargs = {}
effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestDismissApproval object at 0x7fe93f798e10>

    def test_dismiss_approval_failure(self):
        """Test approval dismissal failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_review = Mock()
            mock_review.dismiss.side_effect = Exception("API Error")
            mock_pr = Mock()
            mock_pr.get_review.return_value = mock_review
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.dismiss_approval(123456, "owner/repo", 42, 999)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:512: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fe93b1b39d0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
review_id = 999, message = 'Approval dismissed by Stampbot'

    def dismiss_approval(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        review_id: int,
        message: str = "Approval dismissed by Stampbot",
    ) -> bool:
        """Dismiss a pull request approval.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            review_id: Review ID to dismiss
            message: Dismissal message
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.dismiss_approval",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.review_id": review_id,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get the review and dismiss it
                review = pr.get_review(review_id)
                review.dismiss(message)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                github_api_requests_total.labels(operation="dismiss", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "dismissed"})
                set_span_ok(span)
    
                logger.info(
                    f"Dismissed approval for PR #{pr_number} in {repo_full_name}",
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                        "review_id": review_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() | start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/github_client.py:414: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestDismissApproval::test_dismiss_approval_failure - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 57 passed, 3 deselected, 1 warning in 2.26s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 8, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -466,7 +466,7 @@
 
                 content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                 if isinstance(content, list):
-                    duration = time.time() - start_time
+                    duration = time.time() | start_time
                     github_api_request_duration_seconds.labels(operation="get_file").observe(
                         duration
                     )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 9, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -475,7 +475,7 @@
                     set_span_ok(span)
                     return None
 
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="success").inc()
 
..........................................................F
=================================== FAILURES ===================================
__________________ TestGetRepoFile.test_get_repo_file_success __________________

self = <tests.test_github_client.TestGetRepoFile object at 0x7fda94c70f50>

    def test_get_repo_file_success(self):
        """Test successful file retrieval."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_content = Mock()
            mock_content.decoded_content = b"file content"
            mock_repo = Mock()
            mock_repo.get_contents.return_value = mock_content
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_repo_file(123456, "owner/repo", "stampbot.toml")
    
>           assert result == "file content"
E           AssertionError: assert None == 'file content'

tests/test_github_client.py:557: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:36:02 [debug    ] Could not fetch stampbot.toml from owner/repo: unsupported operand type(s) for |: 'float' and 'float' extra={'repo': 'owner/repo', 'file_path': 'stampbot.toml', 'installation_id': 123456}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetRepoFile::test_get_repo_file_success - AssertionError: assert None == 'file content'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 58 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 10, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -487,7 +487,7 @@
                 return content.decoded_content.decode("utf-8")
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="not_found").inc()
 
............................................................F
=================================== FAILURES ===================================
___________ TestGetRepoFile.test_get_repo_file_returns_none_on_error ___________

self = <stampbot.github_client.GitHubAppClient object at 0x7f842706a6d0>
installation_id = 123456, repo_full_name = 'owner/repo'
file_path = 'nonexistent.toml', ref = None

    def get_repo_file(
        self,
        installation_id: int,
        repo_full_name: str,
        file_path: str,
        ref: str | None = None,
    ) -> str | None:
        """Get file content from repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            file_path: Path to file in repository
            ref: Git reference (branch, tag, commit). Defaults to default branch
    
        Returns:
            File content as string, or None if not found
        """
        start_time = time.time()
    
        with create_span(
            "github.get_file",
            {
                "github.repo": repo_full_name,
                "github.file_path": file_path,
                "github.ref": ref or "default",
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
>               content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:467: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_contents' id='140205497766240'>
args = ('nonexistent.toml',), kwargs = {'ref': None}
effect = Exception('File not found')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: File not found

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetRepoFile object at 0x7f842706c770>

    def test_get_repo_file_returns_none_on_error(self):
        """Test that get_repo_file returns None when file not found."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_contents.side_effect = Exception("File not found")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_repo_file(123456, "owner/repo", "nonexistent.toml")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:628: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f842706a6d0>
installation_id = 123456, repo_full_name = 'owner/repo'
file_path = 'nonexistent.toml', ref = None

    def get_repo_file(
        self,
        installation_id: int,
        repo_full_name: str,
        file_path: str,
        ref: str | None = None,
    ) -> str | None:
        """Get file content from repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            file_path: Path to file in repository
            ref: Git reference (branch, tag, commit). Defaults to default branch
    
        Returns:
            File content as string, or None if not found
        """
        start_time = time.time()
    
        with create_span(
            "github.get_file",
            {
                "github.repo": repo_full_name,
                "github.file_path": file_path,
                "github.ref": ref or "default",
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
                content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                if isinstance(content, list):
                    duration = time.time() - start_time
                    github_api_request_duration_seconds.labels(operation="get_file").observe(
                        duration
                    )
                    github_api_requests_total.labels(operation="get_file", status="not_found").inc()
                    add_span_attributes(span, {"github.result": "not_found"})
                    set_span_ok(span)
                    return None
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                github_api_requests_total.labels(operation="get_file", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "found"})
                set_span_ok(span)
    
                return content.decoded_content.decode("utf-8")
    
            except Exception as e:
>               duration = time.time() | start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/github_client.py:490: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetRepoFile::test_get_repo_file_returns_none_on_error - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 60 passed, 3 deselected, 1 warning in 2.26s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 11, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -546,7 +546,7 @@
                     if review.user.login == bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7f2794d811d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [] == [123]
E             
E             Right contains one more item: 123
E             
E             Full diff:
E             + []
E             - [
E             -     123,
E             - ]

tests/test_github_client.py:685: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:25:31 [error    ] Failed to find bot reviews for PR #42 in owner/repo: unsupported operand type(s) for |: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for |: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [] == [123]
  
  Right contains one more item: 123
  
  Full diff:
  + []
  - [
  -     123,
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 12, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -562,7 +562,7 @@
                 return bot_review_ids
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
..............................................................F
=================================== FAILURES ===================================
_______ TestFindBotReviews.test_find_bot_reviews_returns_empty_on_error ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f03125dc2f0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[int]:
        """Find all reviews created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            List of review IDs created by the bot
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:535: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='139651167925120'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestFindBotReviews object at 0x7f03167b1310>

    def test_find_bot_reviews_returns_empty_on_error(self):
        """Test that find_bot_reviews returns empty list on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.find_bot_reviews(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:717: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f03125dc2f0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[int]:
        """Find all reviews created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            List of review IDs created by the bot
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get bot user via JWT-authenticated integration (installation tokens
                # cannot call GET /user, which is restricted by GitHub Apps integration)
                app_info = self.integration.get_app()
                bot_user = f"{app_info.slug}[bot]"
    
                # Find all reviews by bot that are approvals
                bot_review_ids = []
                for review in pr.get_reviews():
                    if review.user.login == bot_user and review.state == "APPROVED":
                        bot_review_ids.append(review.id)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                    duration
                )
                github_api_requests_total.labels(operation="find_reviews", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span, {"github.reviews_found": len(bot_review_ids), "github.bot_user": bot_user}
                )
                set_span_ok(span)
    
                return bot_review_ids
    
            except Exception as e:
>               duration = time.time() | start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/github_client.py:565: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_returns_empty_on_error - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 62 passed, 3 deselected, 1 warning in 2.30s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 13, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -634,7 +634,7 @@
                             }
                         )
 
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
...............................................................F
=================================== FAILURES ===================================
______ TestFindBotApprovalReviews.test_find_bot_approval_reviews_success _______

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7ff3b1e3d450>

    def test_find_bot_approval_reviews_success(self):
        """Test successful bot approval review state lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            bot_approved_review = Mock()
            bot_approved_review.user.login = "stampbot[bot]"
            bot_approved_review.state = "APPROVED"
            bot_approved_review.id = 123
            bot_approved_review.commit_id = "headsha"
    
            bot_dismissed_review = Mock()
            bot_dismissed_review.user.login = "stampbot[bot]"
            bot_dismissed_review.state = "DISMISSED"
            bot_dismissed_review.id = 124
            bot_dismissed_review.commit_id = "oldsha"
    
            bot_commented_review = Mock()
            bot_commented_review.user.login = "stampbot[bot]"
            bot_commented_review.state = "COMMENTED"
            bot_commented_review.id = 125
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [
                bot_approved_review,
                bot_dismissed_review,
                bot_commented_review,
                other_review,
            ]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
    
>           assert result == [
                {"id": 123, "state": "APPROVED", "commit_id": "headsha"},
                {"id": 124, "state": "DISMISSED", "commit_id": "oldsha"},
            ]
E           AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
E             
E             Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
E             
E             Full diff:
E             + []
E             - [
E             -     {
E             -         'commit_id': 'headsha',
E             -         'id': 123,
E             -         'state': 'APPROVED',
E             -     },
E             -     {
E             -         'commit_id': 'oldsha',
E             -         'id': 124,
E             -         'state': 'DISMISSED',
E             -     },
E             - ]

tests/test_github_client.py:790: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:40:39 [error    ] Failed to find bot approval reviews for PR #42 in owner/repo: unsupported operand type(s) for |: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for |: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_success - AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
  
  Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
  
  Full diff:
  + []
  - [
  -     {
  -         'commit_id': 'headsha',
  -         'id': 123,
  -         'state': 'APPROVED',
  -     },
  -     {
  -         'commit_id': 'oldsha',
  -         'id': 124,
  -         'state': 'DISMISSED',
  -     },
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 63 passed, 3 deselected, 1 warning in 2.13s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 14, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -650,7 +650,7 @@
                 return bot_reviews
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
................................................................F
=================================== FAILURES ===================================
_ TestFindBotApprovalReviews.test_find_bot_approval_reviews_returns_empty_on_error _

self = <stampbot.github_client.GitHubAppClient object at 0x7f5c61043e30>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_approval_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[BotReview]:
        """Find approval review states created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Review state details for bot approval reviews.
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_approval_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:615: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140034741439856'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7f5c65599590>

    def test_find_bot_approval_reviews_returns_empty_on_error(self):
        """Test that find_bot_approval_reviews returns empty list on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:825: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f5c61043e30>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_approval_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[BotReview]:
        """Find approval review states created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Review state details for bot approval reviews.
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_approval_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get bot user via JWT-authenticated integration (installation tokens
                # cannot call GET /user, which is restricted by GitHub Apps integration)
                app_info = self.integration.get_app()
                bot_user = f"{app_info.slug}[bot]"
    
                bot_reviews: list[BotReview] = []
                for review in pr.get_reviews():
                    if review.user.login == bot_user and review.state in (
                        "APPROVED",
                        "DISMISSED",
                    ):
                        bot_reviews.append(
                            {
                                "id": review.id,
                                "state": review.state,
                                "commit_id": getattr(review, "commit_id", None),
                            }
                        )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                    duration
                )
                github_api_requests_total.labels(operation="find_reviews", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span, {"github.reviews_found": len(bot_reviews), "github.bot_user": bot_user}
                )
                set_span_ok(span)
    
                return bot_reviews
    
            except Exception as e:
>               duration = time.time() | start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/github_client.py:653: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_returns_empty_on_error - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 64 passed, 3 deselected, 1 warning in 2.27s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 15, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -707,7 +707,7 @@
 
                 pr.create_review(body=message, event="COMMENT")
 
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="success").inc()
 
........................................................................ [ 30%]
......F
=================================== FAILURES ===================================
_______ TestCreatePrReviewComment.test_create_pr_review_comment_success ________

self = <tests.test_github_client.TestCreatePrReviewComment object at 0x7f1fcc0e1e50>

    def test_create_pr_review_comment_success(self):
        """Test successful review comment creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_pr_review_comment(
                123456,
                "owner/repo",
                42,
                "Config error",
            )
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:1398: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:29:37 [warning  ] Failed to post config error review for PR #42 in owner/repo: unsupported operand type(s) for |: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for |: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreatePrReviewComment::test_create_pr_review_comment_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 78 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 16, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -729,7 +729,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="failure").inc()
 
........................................................................ [ 30%]
.......F
=================================== FAILURES ===================================
_______ TestCreatePrReviewComment.test_create_pr_review_comment_failure ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f1499506db0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
message = 'Config error'

    def create_pr_review_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
    ) -> bool:
        """Create a comment review on a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            message: Review comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_review_comment",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               pr = repo.get_pull(pr_number)
                     ^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:706: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull' id='139726449538928'>
args = (42,), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestCreatePrReviewComment object at 0x7f149d949f90>

    def test_create_pr_review_comment_failure(self):
        """Test review comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_pull.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.create_pr_review_comment(
                123456,
                "owner/repo",
                42,
                "Config error",
            )

tests/test_github_client.py:1433: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f1499506db0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
message = 'Config error'

    def create_pr_review_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
    ) -> bool:
        """Create a comment review on a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            message: Review comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_review_comment",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                pr.create_review(body=message, event="COMMENT")
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                github_api_requests_total.labels(operation="comment", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "commented"})
                set_span_ok(span)
    
                logger.info(
                    "Posted config error review on PR #%d in %s",
                    pr_number,
                    repo_full_name,
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() | start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/github_client.py:732: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreatePrReviewComment::test_create_pr_review_comment_failure - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 79 passed, 3 deselected, 1 warning in 2.30s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 17, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -784,7 +784,7 @@
 
                 issue.create_comment(message)
 
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........F
=================================== FAILURES ===================================
___________ TestCreateIssueComment.test_create_issue_comment_success ___________

self = <tests.test_github_client.TestCreateIssueComment object at 0x7f4269b720d0>

    def test_create_issue_comment_success(self):
        """Test successful issue comment creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_issue = Mock()
            mock_repo = Mock()
            mock_repo.get_issue.return_value = mock_issue
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_issue_comment(
                123456,
                "owner/repo",
                42,
                "Help text",
            )
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:1487: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:22:40 [warning  ] Failed to post issue comment on #42 in owner/repo: unsupported operand type(s) for |: 'float' and 'float' extra={'repo': 'owner/repo', 'issue_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for |: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreateIssueComment::test_create_issue_comment_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 80 passed, 3 deselected, 1 warning in 2.19s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 18, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -808,7 +808,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
.........F
=================================== FAILURES ===================================
___________ TestCreateIssueComment.test_create_issue_comment_failure ___________

self = <stampbot.github_client.GitHubAppClient object at 0x7f12151deed0>
installation_id = 123456, repo_full_name = 'owner/repo', issue_number = 42
message = 'Help text'

    def create_issue_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        issue_number: int,
        message: str,
    ) -> bool:
        """Create a comment on an issue or pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            issue_number: Issue or pull request number
            message: Comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_issue_comment",
            {
                "github.repo": repo_full_name,
                "github.issue_number": issue_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               issue = repo.get_issue(issue_number)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:783: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_issue' id='139715640224336'>
args = (42,), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestCreateIssueComment object at 0x7f12194d2210>

    def test_create_issue_comment_failure(self):
        """Test issue comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_issue.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.create_issue_comment(
                123456,
                "owner/repo",
                42,
                "Help text",
            )

tests/test_github_client.py:1523: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f12151deed0>
installation_id = 123456, repo_full_name = 'owner/repo', issue_number = 42
message = 'Help text'

    def create_issue_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        issue_number: int,
        message: str,
    ) -> bool:
        """Create a comment on an issue or pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            issue_number: Issue or pull request number
            message: Comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_issue_comment",
            {
                "github.repo": repo_full_name,
                "github.issue_number": issue_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                issue = repo.get_issue(issue_number)
    
                issue.create_comment(message)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                    duration
                )
                github_api_requests_total.labels(operation="issue_comment", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "commented"})
                set_span_ok(span)
    
                logger.info(
                    "Posted issue comment on #%d in %s",
                    issue_number,
                    repo_full_name,
                    extra={
                        "repo": repo_full_name,
                        "issue_number": issue_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() | start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/github_client.py:811: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreateIssueComment::test_create_issue_comment_failure - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 81 passed, 3 deselected, 1 warning in 2.31s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 19, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -861,7 +861,7 @@
                 repo = client.get_repo(repo_full_name)
                 repo.get_label(label_name)
 
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="success").inc()
 
........................................................................ [ 30%]
..F
=================================== FAILURES ===================================
__________________ TestRepoHasLabel.test_repo_has_label_true ___________________

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f97464ddbd0>

    def test_repo_has_label_true(self):
        """Test repo_has_label returns True when label exists."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.return_value = Mock()
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.repo_has_label(123456, "owner/repo", "autoapprove")
    
>           assert result is True
E           assert None is True

tests/test_github_client.py:1239: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:59:42 [debug    ] Could not verify label autoapprove in owner/repo: unsupported operand type(s) for |: 'float' and 'float' extra={'repo': 'owner/repo', 'label': 'autoapprove', 'installation_id': 123456, 'error': "unsupported operand type(s) for |: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_true - assert None is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 74 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 20, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -872,7 +872,7 @@
                 return True
 
             except GithubException as e:
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
...F
=================================== FAILURES ===================================
________________ TestRepoHasLabel.test_repo_has_label_not_found ________________

self = <stampbot.github_client.GitHubAppClient object at 0x7f77412f1df0>
installation_id = 123456, repo_full_name = 'owner/repo', label_name = 'missing'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               repo.get_label(label_name)

stampbot/github_client.py:862: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_label' id='140150170572784'>
args = ('missing',), kwargs = {}
effect = GithubException(404 {"message": "Not Found"})

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               github.GithubException.GithubException: 404 {"message": "Not Found"}

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: GithubException

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f7745611d10>

    def test_repo_has_label_not_found(self):
        """Test repo_has_label returns False when label is missing."""
        from github.GithubException import GithubException
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = GithubException(404, {"message": "Not Found"}, None)
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.repo_has_label(123456, "owner/repo", "missing")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1275: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f77412f1df0>
installation_id = 123456, repo_full_name = 'owner/repo', label_name = 'missing'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                repo.get_label(label_name)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.label_found": True})
                set_span_ok(span)
                return True
    
            except GithubException as e:
>               duration = time.time() | start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/github_client.py:875: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_not_found - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 75 passed, 3 deselected, 1 warning in 2.29s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 21, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -897,7 +897,7 @@
                 return None
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
.....F
=================================== FAILURES ===================================
__________________ TestRepoHasLabel.test_repo_has_label_error __________________

self = <stampbot.github_client.GitHubAppClient object at 0x7f36661c7e30>
installation_id = 123456, repo_full_name = 'owner/repo'
label_name = 'autoapprove'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               repo.get_label(label_name)

stampbot/github_client.py:862: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_label' id='139871617524672'>
args = ('autoapprove',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f366a354e90>

    def test_repo_has_label_error(self):
        """Test repo_has_label returns None on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.repo_has_label(123456, "owner/repo", "autoapprove")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1349: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f36661c7e30>
installation_id = 123456, repo_full_name = 'owner/repo'
label_name = 'autoapprove'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                repo.get_label(label_name)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.label_found": True})
                set_span_ok(span)
                return True
    
            except GithubException as e:
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="failure").inc()
    
                if e.status == 404:
                    add_span_attributes(span, {"github.label_found": False})
                    set_span_ok(span)
                    return False
    
                set_span_error(span, e)
                logger.debug(
                    "Could not verify label %s in %s: %s",
                    label_name,
                    repo_full_name,
                    _sanitize_error(e),
                    extra={
                        "repo": repo_full_name,
                        "label": label_name,
                        "installation_id": installation_id,
                        "error": _sanitize_error(e),
                    },
                )
                return None
    
            except Exception as e:
>               duration = time.time() | start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/github_client.py:900: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_error - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 77 passed, 3 deselected, 1 warning in 2.32s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 22, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -960,7 +960,7 @@
 
                 has_permission = permission_index >= required_index
 
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
.................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_true ______________

self = <tests.test_github_client.TestUserHasPermission object at 0x7fee1c9896d0>

    def test_user_has_permission_true(self):
        """Test required permission satisfied returns True."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.return_value = "write"
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.user_has_permission(123456, "owner/repo", "alice", "write")
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:868: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:40:49 [warning  ] Failed to check collaborator permission for alice in owner/repo: unsupported operand type(s) for |: 'float' and 'float' extra={'repo': 'owner/repo', 'username': 'alice', 'installation_id': 123456, 'error': "unsupported operand type(s) for |: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_true - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 65 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 23, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -980,7 +980,7 @@
                 return has_permission
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
...................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_error _____________

self = <stampbot.github_client.GitHubAppClient object at 0x7fc891838110>
installation_id = 123456, repo_full_name = 'owner/repo', username = 'carol'
required_permission = 'maintain'

    def user_has_permission(
        self,
        installation_id: int,
        repo_full_name: str,
        username: str,
        required_permission: str,
    ) -> bool:
        """Check whether a user has required access to a repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            username: GitHub username to check
            required_permission: Minimum required repository permission
    
        Returns:
            True if user meets or exceeds required permission, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.get_collaborator_permission",
            {
                "github.repo": repo_full_name,
                "github.username": username,
                "github.required_permission": required_permission,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
>               permission = repo.get_collaborator_permission(username)
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:952: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_collaborator_permission' id='140499411525920'>
args = ('carol',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestUserHasPermission object at 0x7fc895a3c8a0>

    def test_user_has_permission_error(self):
        """Test permission check returns False on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.user_has_permission(123456, "owner/repo", "carol", "maintain")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:939: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fc891838110>
installation_id = 123456, repo_full_name = 'owner/repo', username = 'carol'
required_permission = 'maintain'

    def user_has_permission(
        self,
        installation_id: int,
        repo_full_name: str,
        username: str,
        required_permission: str,
    ) -> bool:
        """Check whether a user has required access to a repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            username: GitHub username to check
            required_permission: Minimum required repository permission
    
        Returns:
            True if user meets or exceeds required permission, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.get_collaborator_permission",
            {
                "github.repo": repo_full_name,
                "github.username": username,
                "github.required_permission": required_permission,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
                permission = repo.get_collaborator_permission(username)
                permission_order = ["none", "read", "triage", "write", "maintain", "admin"]
                try:
                    permission_index = permission_order.index(permission)
                    required_index = permission_order.index(required_permission)
                except ValueError:
                    permission_index = -1
                    required_index = 99
    
                has_permission = permission_index >= required_index
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_permission").observe(
                    duration
                )
                github_api_requests_total.labels(operation="get_permission", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span,
                    {
                        "github.permission": permission,
                        "github.has_permission": has_permission,
                    },
                )
                set_span_ok(span)
    
                return has_permission
    
            except Exception as e:
>               duration = time.time() | start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/github_client.py:983: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_error - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 67 passed, 3 deselected, 1 warning in 2.31s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 24, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1071,7 +1071,7 @@
                         )
                         continue
 
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
.....................................................................F
=================================== FAILURES ===================================
____________ TestGetUserTeamSlugs.test_get_user_team_slugs_success _____________

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7fce92f71950>

    def test_get_user_team_slugs_success(self):
        """Test successful team membership check."""
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            # Mock user
            mock_user = Mock()
            mock_user.login = "alice"
    
            # Mock team that has alice as member
            mock_team = Mock()
            mock_team.has_in_members.return_value = True
    
            # Mock org
            mock_org = Mock()
            mock_org.get_team_by_slug.return_value = mock_team
    
            mock_github = Mock()
            mock_github.get_organization.return_value = mock_org
            mock_github.get_user.return_value = mock_user
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_user_team_slugs(
                123456, "acme", "alice", ["release-team", "deploy-team"]
            )
    
>           assert result == ["release-team", "deploy-team"]
E           AssertionError: assert [] == ['release-tea...'deploy-team']
E             
E             Right contains 2 more items, first extra item: 'release-team'
E             
E             Full diff:
E             + []
E             - [
E             -     'release-team',
E             -     'deploy-team',
E             - ]

tests/test_github_client.py:1033: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:33:11 [debug    ] User alice is a member of team release-team extra={'org': 'acme', 'username': 'alice', 'team': 'release-team'}
2026-06-29 05:33:11 [debug    ] User alice is a member of team deploy-team extra={'org': 'acme', 'username': 'alice', 'team': 'deploy-team'}
2026-06-29 05:33:11 [warning  ] Failed to check team memberships for alice in acme: unsupported operand type(s) for |: 'float' and 'float' extra={'org': 'acme', 'username': 'alice', 'installation_id': 123456, 'error': "unsupported operand type(s) for |: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_success - AssertionError: assert [] == ['release-tea...'deploy-team']
  
  Right contains 2 more items, first extra item: 'release-team'
  
  Full diff:
  + []
  - [
  -     'release-team',
  -     'deploy-team',
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 69 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 25, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1091,7 +1091,7 @@
                 return member_teams
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() | start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
.F
=================================== FAILURES ===================================
_______ TestGetUserTeamSlugs.test_get_user_team_slugs_general_exception ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f24debc3830>
installation_id = 123456, org_name = 'acme', username = 'alice'
allowed_teams = ['release-team']

    def get_user_team_slugs(
        self,
        installation_id: int,
        org_name: str,
        username: str,
        allowed_teams: list[str],
    ) -> list[str]:
        """Get team slugs the user is a member of from the allowed teams list.
    
        Args:
            installation_id: GitHub App installation ID
            org_name: Organization name
            username: GitHub username to check
            allowed_teams: List of team slugs to check (can be "org/team" or just "team")
    
        Returns:
            List of team slugs the user is a member of
        """
        start_time = time.time()
    
        with create_span(
            "github.get_user_team_slugs",
            {
                "github.org": org_name,
                "github.username": username,
                "github.installation_id": installation_id,
                "github.teams_to_check": len(allowed_teams),
            },
        ) as span:
            member_teams: list[str] = []
    
            try:
                client = self._get_installation_client(installation_id)
>               org = client.get_organization(org_name)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:1038: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_organization' id='139796331848640'>
args = ('acme',), kwargs = {}, effect = Exception('Network error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Network error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7f24e32ffe30>

    def test_get_user_team_slugs_general_exception(self):
        """Test team membership check with general exception."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_organization.side_effect = Exception("Network error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_user_team_slugs(123456, "acme", "alice", ["release-team"])
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1195: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f24debc3830>
installation_id = 123456, org_name = 'acme', username = 'alice'
allowed_teams = ['release-team']

    def get_user_team_slugs(
        self,
        installation_id: int,
        org_name: str,
        username: str,
        allowed_teams: list[str],
    ) -> list[str]:
        """Get team slugs the user is a member of from the allowed teams list.
    
        Args:
            installation_id: GitHub App installation ID
            org_name: Organization name
            username: GitHub username to check
            allowed_teams: List of team slugs to check (can be "org/team" or just "team")
    
        Returns:
            List of team slugs the user is a member of
        """
        start_time = time.time()
    
        with create_span(
            "github.get_user_team_slugs",
            {
                "github.org": org_name,
                "github.username": username,
                "github.installation_id": installation_id,
                "github.teams_to_check": len(allowed_teams),
            },
        ) as span:
            member_teams: list[str] = []
    
            try:
                client = self._get_installation_client(installation_id)
                org = client.get_organization(org_name)
    
                for team_ref in allowed_teams:
                    # Extract team slug (handle both "org/team" and "team" formats)
                    team_slug = team_ref.split("/")[-1] if "/" in team_ref else team_ref
    
                    try:
                        team = org.get_team_by_slug(team_slug)
                        # Check if user is a member
                        user = client.get_user(username)
                        if team.has_in_members(user):  # type: ignore[arg-type]
                            member_teams.append(team_slug)
                            logger.debug(
                                "User %s is a member of team %s",
                                username,
                                team_slug,
                                extra={
                                    "org": org_name,
                                    "username": username,
                                    "team": team_slug,
                                },
                            )
                    except GithubException as e:
                        # Team not found or no access - skip silently
                        logger.debug(
                            "Could not check team %s membership: %s",
                            team_slug,
                            e.data.get("message", str(e)) if hasattr(e, "data") else str(e),
                            extra={
                                "org": org_name,
                                "team": team_slug,
                                "username": username,
                            },
                        )
                        continue
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                    duration
                )
                github_api_requests_total.labels(operation="get_user_teams", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span,
                    {
                        "github.member_teams": len(member_teams),
                        "github.teams_checked": len(allowed_teams),
                    },
                )
                set_span_ok(span)
    
                return member_teams
    
            except Exception as e:
>               duration = time.time() | start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/github_client.py:1094: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_general_exception - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 73 passed, 3 deselected, 1 warning in 2.30s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 0, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -177,7 +177,7 @@
                     retry=retry,
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="success").inc()
 
................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_success ________

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f8744f782d0>

    def test_get_installation_client_success(self):
        """Test successful installation client creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client._get_installation_client(123456)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:211: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f8741dfd8d0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
                auth = self.integration.get_access_token(installation_id)
    
                # Configure retry with exponential backoff
                retry = Retry(
                    total=GITHUB_API_RETRY_TOTAL,
                    backoff_factor=GITHUB_API_RETRY_BACKOFF,
                    status_forcelist=[500, 502, 503, 504],
                    allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                )
    
                client = Github(
                    auth=Auth.Token(auth.token),
                    timeout=GITHUB_API_TIMEOUT,
                    retry=retry,
                )
    
>               duration = time.time() & start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/github_client.py:180: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_success - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 48 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 1, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -185,7 +185,7 @@
                 return client
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="failure").inc()
                 set_span_error(span, e)
.................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_failure ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f639a5736c0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
>               auth = self.integration.get_access_token(installation_id)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:164: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='GithubIntegration().get_access_token' id='140065722517888'>
args = (123456,), kwargs = {}, effect = Exception('Token exchange failed')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Token exchange failed

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f639bfd8410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            with pytest.raises(Exception, match="Token exchange failed"):
>               client._get_installation_client(123456)

tests/test_github_client.py:240: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f639a5736c0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
                auth = self.integration.get_access_token(installation_id)
    
                # Configure retry with exponential backoff
                retry = Retry(
                    total=GITHUB_API_RETRY_TOTAL,
                    backoff_factor=GITHUB_API_RETRY_BACKOFF,
                    status_forcelist=[500, 502, 503, 504],
                    allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                )
    
                client = Github(
                    auth=Auth.Token(auth.token),
                    timeout=GITHUB_API_TIMEOUT,
                    retry=retry,
                )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                github_api_requests_total.labels(operation="get_token", status="success").inc()
    
                set_span_ok(span)
                return client
    
            except Exception as e:
>               duration = time.time() & start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/github_client.py:188: TypeError

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f639bfd8410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           with pytest.raises(Exception, match="Token exchange failed"):
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           AssertionError: Regex pattern did not match.
E             Expected regex: 'Token exchange failed'
E             Actual message: "unsupported operand type(s) for &: 'float' and 'float'"

tests/test_github_client.py:239: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_failure - AssertionError: Regex pattern did not match.
  Expected regex: 'Token exchange failed'
  Actual message: "unsupported operand type(s) for &: 'float' and 'float'"
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 49 passed, 3 deselected, 1 warning in 2.25s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 2, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -249,7 +249,7 @@
                     event="APPROVE",
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="success").inc()
 
....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_success _____________________

self = <tests.test_github_client.TestApprovePR object at 0x7f1421e6c7d0>

    def test_approve_pr_success(self):
        """Test successful PR approval."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.approve_pr(123456, "owner/repo", 42)
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:313: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:14:37 [error    ] Failed to approve PR #42 in owner/repo: unsupported operand type(s) for &: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for &: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 52 passed, 3 deselected, 1 warning in 2.13s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 3, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -269,7 +269,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="failure").inc()
 
.....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_failure _____________________

self = <stampbot.github_client.GitHubAppClient object at 0x7f1f3c1fe620>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
comment = 'Auto-approved by Stampbot'

    def approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str = "Auto-approved by Stampbot",
    ) -> bool:
        """Approve a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            comment: Review comment
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Create approval review
>               pr.create_review(
                    body=comment,
                    event="APPROVE",
                )

stampbot/github_client.py:247: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull().create_review' id='139772110719696'>
args = (), kwargs = {'body': 'Auto-approved by Stampbot', 'event': 'APPROVE'}
effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestApprovePR object at 0x7f1f3f660910>

    def test_approve_pr_failure(self):
        """Test PR approval failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_pr.create_review.side_effect = Exception("API Error")
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.approve_pr(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:350: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f1f3c1fe620>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
comment = 'Auto-approved by Stampbot'

    def approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str = "Auto-approved by Stampbot",
    ) -> bool:
        """Approve a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            comment: Review comment
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Create approval review
                pr.create_review(
                    body=comment,
                    event="APPROVE",
                )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                github_api_requests_total.labels(operation="approve", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "approved"})
                set_span_ok(span)
    
                logger.info(
                    f"Approved PR #{pr_number} in {repo_full_name}",
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() & start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/github_client.py:272: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_failure - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 53 passed, 3 deselected, 1 warning in 2.26s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 4, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -318,7 +318,7 @@
                 pr = repo.get_pull(pr_number)
                 head_sha: str = pr.head.sha
 
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="success").inc()
 
......................................................F
=================================== FAILURES ===================================
________________ TestGetPRHeadSHA.test_get_pr_head_sha_success _________________

self = <tests.test_github_client.TestGetPRHeadSHA object at 0x7f0f33880a50>

    def test_get_pr_head_sha_success(self):
        """Test successful PR head SHA lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_pr.head.sha = "current-head"
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_pr_head_sha(123456, "owner/repo", 42)
    
>           assert result == "current-head"
E           AssertionError: assert None == 'current-head'

tests/test_github_client.py:395: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:34:47 [error    ] Failed to get head SHA for PR #42 in owner/repo: unsupported operand type(s) for &: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for &: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetPRHeadSHA::test_get_pr_head_sha_success - AssertionError: assert None == 'current-head'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 54 passed, 3 deselected, 1 warning in 2.11s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 5, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -330,7 +330,7 @@
                 return head_sha
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="failure").inc()
 
.......................................................F
=================================== FAILURES ===================================
_________ TestGetPRHeadSHA.test_get_pr_head_sha_returns_none_on_error __________

self = <stampbot.github_client.GitHubAppClient object at 0x7f9e5a9c2530>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def get_pr_head_sha(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> str | None:
        """Get the current head SHA for a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Current pull request head SHA, or None on error.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_pr_head_sha",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:317: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140318099917520'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetPRHeadSHA object at 0x7f9e5eb90b90>

    def test_get_pr_head_sha_returns_none_on_error(self):
        """Test PR head SHA lookup returns None on API errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_pr_head_sha(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:427: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f9e5a9c2530>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def get_pr_head_sha(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> str | None:
        """Get the current head SHA for a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Current pull request head SHA, or None on error.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_pr_head_sha",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
                head_sha: str = pr.head.sha
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                github_api_requests_total.labels(operation="get_pull", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.head_sha": head_sha})
                set_span_ok(span)
    
                return head_sha
    
            except Exception as e:
>               duration = time.time() & start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/github_client.py:333: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetPRHeadSHA::test_get_pr_head_sha_returns_none_on_error - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 55 passed, 3 deselected, 1 warning in 2.25s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 6, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -390,7 +390,7 @@
                 review = pr.get_review(review_id)
                 review.dismiss(message)
 
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="success").inc()
 
........................................................F
=================================== FAILURES ===================================
______________ TestDismissApproval.test_dismiss_approval_success _______________

self = <tests.test_github_client.TestDismissApproval object at 0x7fb49dd98cd0>

    def test_dismiss_approval_success(self):
        """Test successful approval dismissal."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_review = Mock()
            mock_pr = Mock()
            mock_pr.get_review.return_value = mock_review
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.dismiss_approval(123456, "owner/repo", 42, 999)
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:473: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:21:23 [error    ] Failed to dismiss approval for PR #42 in owner/repo: unsupported operand type(s) for &: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for &: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestDismissApproval::test_dismiss_approval_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 56 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 7, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -411,7 +411,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="failure").inc()
 
.........................................................F
=================================== FAILURES ===================================
______________ TestDismissApproval.test_dismiss_approval_failure _______________

self = <stampbot.github_client.GitHubAppClient object at 0x7f125cebfa50>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
review_id = 999, message = 'Approval dismissed by Stampbot'

    def dismiss_approval(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        review_id: int,
        message: str = "Approval dismissed by Stampbot",
    ) -> bool:
        """Dismiss a pull request approval.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            review_id: Review ID to dismiss
            message: Dismissal message
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.dismiss_approval",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.review_id": review_id,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get the review and dismiss it
                review = pr.get_review(review_id)
>               review.dismiss(message)

stampbot/github_client.py:391: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull().get_review().dismiss' id='139716845346768'>
args = ('Approval dismissed by Stampbot',), kwargs = {}
effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestDismissApproval object at 0x7f12610b0e10>

    def test_dismiss_approval_failure(self):
        """Test approval dismissal failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_review = Mock()
            mock_review.dismiss.side_effect = Exception("API Error")
            mock_pr = Mock()
            mock_pr.get_review.return_value = mock_review
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.dismiss_approval(123456, "owner/repo", 42, 999)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:512: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f125cebfa50>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
review_id = 999, message = 'Approval dismissed by Stampbot'

    def dismiss_approval(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        review_id: int,
        message: str = "Approval dismissed by Stampbot",
    ) -> bool:
        """Dismiss a pull request approval.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            review_id: Review ID to dismiss
            message: Dismissal message
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.dismiss_approval",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.review_id": review_id,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get the review and dismiss it
                review = pr.get_review(review_id)
                review.dismiss(message)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                github_api_requests_total.labels(operation="dismiss", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "dismissed"})
                set_span_ok(span)
    
                logger.info(
                    f"Dismissed approval for PR #{pr_number} in {repo_full_name}",
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                        "review_id": review_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() & start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/github_client.py:414: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestDismissApproval::test_dismiss_approval_failure - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 57 passed, 3 deselected, 1 warning in 2.27s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 8, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -466,7 +466,7 @@
 
                 content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                 if isinstance(content, list):
-                    duration = time.time() - start_time
+                    duration = time.time() & start_time
                     github_api_request_duration_seconds.labels(operation="get_file").observe(
                         duration
                     )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 9, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -475,7 +475,7 @@
                     set_span_ok(span)
                     return None
 
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="success").inc()
 
..........................................................F
=================================== FAILURES ===================================
__________________ TestGetRepoFile.test_get_repo_file_success __________________

self = <tests.test_github_client.TestGetRepoFile object at 0x7fde1f4d0f50>

    def test_get_repo_file_success(self):
        """Test successful file retrieval."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_content = Mock()
            mock_content.decoded_content = b"file content"
            mock_repo = Mock()
            mock_repo.get_contents.return_value = mock_content
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_repo_file(123456, "owner/repo", "stampbot.toml")
    
>           assert result == "file content"
E           AssertionError: assert None == 'file content'

tests/test_github_client.py:557: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:06:08 [debug    ] Could not fetch stampbot.toml from owner/repo: unsupported operand type(s) for &: 'float' and 'float' extra={'repo': 'owner/repo', 'file_path': 'stampbot.toml', 'installation_id': 123456}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetRepoFile::test_get_repo_file_success - AssertionError: assert None == 'file content'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 58 passed, 3 deselected, 1 warning in 2.12s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 10, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -487,7 +487,7 @@
                 return content.decoded_content.decode("utf-8")
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="not_found").inc()
 
............................................................F
=================================== FAILURES ===================================
___________ TestGetRepoFile.test_get_repo_file_returns_none_on_error ___________

self = <stampbot.github_client.GitHubAppClient object at 0x7f876bbe67b0>
installation_id = 123456, repo_full_name = 'owner/repo'
file_path = 'nonexistent.toml', ref = None

    def get_repo_file(
        self,
        installation_id: int,
        repo_full_name: str,
        file_path: str,
        ref: str | None = None,
    ) -> str | None:
        """Get file content from repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            file_path: Path to file in repository
            ref: Git reference (branch, tag, commit). Defaults to default branch
    
        Returns:
            File content as string, or None if not found
        """
        start_time = time.time()
    
        with create_span(
            "github.get_file",
            {
                "github.repo": repo_full_name,
                "github.file_path": file_path,
                "github.ref": ref or "default",
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
>               content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:467: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_contents' id='140219535675744'>
args = ('nonexistent.toml',), kwargs = {'ref': None}
effect = Exception('File not found')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: File not found

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetRepoFile object at 0x7f876bbec770>

    def test_get_repo_file_returns_none_on_error(self):
        """Test that get_repo_file returns None when file not found."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_contents.side_effect = Exception("File not found")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_repo_file(123456, "owner/repo", "nonexistent.toml")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:628: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f876bbe67b0>
installation_id = 123456, repo_full_name = 'owner/repo'
file_path = 'nonexistent.toml', ref = None

    def get_repo_file(
        self,
        installation_id: int,
        repo_full_name: str,
        file_path: str,
        ref: str | None = None,
    ) -> str | None:
        """Get file content from repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            file_path: Path to file in repository
            ref: Git reference (branch, tag, commit). Defaults to default branch
    
        Returns:
            File content as string, or None if not found
        """
        start_time = time.time()
    
        with create_span(
            "github.get_file",
            {
                "github.repo": repo_full_name,
                "github.file_path": file_path,
                "github.ref": ref or "default",
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
                content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                if isinstance(content, list):
                    duration = time.time() - start_time
                    github_api_request_duration_seconds.labels(operation="get_file").observe(
                        duration
                    )
                    github_api_requests_total.labels(operation="get_file", status="not_found").inc()
                    add_span_attributes(span, {"github.result": "not_found"})
                    set_span_ok(span)
                    return None
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                github_api_requests_total.labels(operation="get_file", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "found"})
                set_span_ok(span)
    
                return content.decoded_content.decode("utf-8")
    
            except Exception as e:
>               duration = time.time() & start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/github_client.py:490: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetRepoFile::test_get_repo_file_returns_none_on_error - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 60 passed, 3 deselected, 1 warning in 2.28s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 11, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -546,7 +546,7 @@
                     if review.user.login == bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7f61100151d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [] == [123]
E             
E             Right contains one more item: 123
E             
E             Full diff:
E             + []
E             - [
E             -     123,
E             - ]

tests/test_github_client.py:685: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:22:35 [error    ] Failed to find bot reviews for PR #42 in owner/repo: unsupported operand type(s) for &: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for &: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [] == [123]
  
  Right contains one more item: 123
  
  Full diff:
  + []
  - [
  -     123,
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 12, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -562,7 +562,7 @@
                 return bot_review_ids
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
..............................................................F
=================================== FAILURES ===================================
_______ TestFindBotReviews.test_find_bot_reviews_returns_empty_on_error ________

self = <stampbot.github_client.GitHubAppClient object at 0x7fb13c5ac410>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[int]:
        """Find all reviews created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            List of review IDs created by the bot
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:535: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140399198761856'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestFindBotReviews object at 0x7fb140b4d310>

    def test_find_bot_reviews_returns_empty_on_error(self):
        """Test that find_bot_reviews returns empty list on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.find_bot_reviews(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:717: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fb13c5ac410>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[int]:
        """Find all reviews created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            List of review IDs created by the bot
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get bot user via JWT-authenticated integration (installation tokens
                # cannot call GET /user, which is restricted by GitHub Apps integration)
                app_info = self.integration.get_app()
                bot_user = f"{app_info.slug}[bot]"
    
                # Find all reviews by bot that are approvals
                bot_review_ids = []
                for review in pr.get_reviews():
                    if review.user.login == bot_user and review.state == "APPROVED":
                        bot_review_ids.append(review.id)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                    duration
                )
                github_api_requests_total.labels(operation="find_reviews", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span, {"github.reviews_found": len(bot_review_ids), "github.bot_user": bot_user}
                )
                set_span_ok(span)
    
                return bot_review_ids
    
            except Exception as e:
>               duration = time.time() & start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/github_client.py:565: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_returns_empty_on_error - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 62 passed, 3 deselected, 1 warning in 2.28s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 13, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -634,7 +634,7 @@
                             }
                         )
 
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
...............................................................F
=================================== FAILURES ===================================
______ TestFindBotApprovalReviews.test_find_bot_approval_reviews_success _______

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7f2f427c9450>

    def test_find_bot_approval_reviews_success(self):
        """Test successful bot approval review state lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            bot_approved_review = Mock()
            bot_approved_review.user.login = "stampbot[bot]"
            bot_approved_review.state = "APPROVED"
            bot_approved_review.id = 123
            bot_approved_review.commit_id = "headsha"
    
            bot_dismissed_review = Mock()
            bot_dismissed_review.user.login = "stampbot[bot]"
            bot_dismissed_review.state = "DISMISSED"
            bot_dismissed_review.id = 124
            bot_dismissed_review.commit_id = "oldsha"
    
            bot_commented_review = Mock()
            bot_commented_review.user.login = "stampbot[bot]"
            bot_commented_review.state = "COMMENTED"
            bot_commented_review.id = 125
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [
                bot_approved_review,
                bot_dismissed_review,
                bot_commented_review,
                other_review,
            ]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
    
>           assert result == [
                {"id": 123, "state": "APPROVED", "commit_id": "headsha"},
                {"id": 124, "state": "DISMISSED", "commit_id": "oldsha"},
            ]
E           AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
E             
E             Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
E             
E             Full diff:
E             + []
E             - [
E             -     {
E             -         'commit_id': 'headsha',
E             -         'id': 123,
E             -         'state': 'APPROVED',
E             -     },
E             -     {
E             -         'commit_id': 'oldsha',
E             -         'id': 124,
E             -         'state': 'DISMISSED',
E             -     },
E             - ]

tests/test_github_client.py:790: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:26:57 [error    ] Failed to find bot approval reviews for PR #42 in owner/repo: unsupported operand type(s) for &: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for &: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_success - AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
  
  Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
  
  Full diff:
  + []
  - [
  -     {
  -         'commit_id': 'headsha',
  -         'id': 123,
  -         'state': 'APPROVED',
  -     },
  -     {
  -         'commit_id': 'oldsha',
  -         'id': 124,
  -         'state': 'DISMISSED',
  -     },
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 63 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 14, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -650,7 +650,7 @@
                 return bot_reviews
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
................................................................F
=================================== FAILURES ===================================
_ TestFindBotApprovalReviews.test_find_bot_approval_reviews_returns_empty_on_error _

self = <stampbot.github_client.GitHubAppClient object at 0x7fdd82a9fe30>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_approval_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[BotReview]:
        """Find approval review states created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Review state details for bot approval reviews.
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_approval_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:615: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140589356617072'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7fdd86fc5590>

    def test_find_bot_approval_reviews_returns_empty_on_error(self):
        """Test that find_bot_approval_reviews returns empty list on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:825: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fdd82a9fe30>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_approval_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[BotReview]:
        """Find approval review states created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Review state details for bot approval reviews.
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_approval_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get bot user via JWT-authenticated integration (installation tokens
                # cannot call GET /user, which is restricted by GitHub Apps integration)
                app_info = self.integration.get_app()
                bot_user = f"{app_info.slug}[bot]"
    
                bot_reviews: list[BotReview] = []
                for review in pr.get_reviews():
                    if review.user.login == bot_user and review.state in (
                        "APPROVED",
                        "DISMISSED",
                    ):
                        bot_reviews.append(
                            {
                                "id": review.id,
                                "state": review.state,
                                "commit_id": getattr(review, "commit_id", None),
                            }
                        )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                    duration
                )
                github_api_requests_total.labels(operation="find_reviews", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span, {"github.reviews_found": len(bot_reviews), "github.bot_user": bot_user}
                )
                set_span_ok(span)
    
                return bot_reviews
    
            except Exception as e:
>               duration = time.time() & start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/github_client.py:653: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_returns_empty_on_error - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 64 passed, 3 deselected, 1 warning in 2.28s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 15, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -707,7 +707,7 @@
 
                 pr.create_review(body=message, event="COMMENT")
 
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="success").inc()
 
........................................................................ [ 30%]
......F
=================================== FAILURES ===================================
_______ TestCreatePrReviewComment.test_create_pr_review_comment_success ________

self = <tests.test_github_client.TestCreatePrReviewComment object at 0x7f204d265e50>

    def test_create_pr_review_comment_success(self):
        """Test successful review comment creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_pr_review_comment(
                123456,
                "owner/repo",
                42,
                "Config error",
            )
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:1398: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:25:37 [warning  ] Failed to post config error review for PR #42 in owner/repo: unsupported operand type(s) for &: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for &: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreatePrReviewComment::test_create_pr_review_comment_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 78 passed, 3 deselected, 1 warning in 2.19s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 16, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -729,7 +729,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="failure").inc()
 
........................................................................ [ 30%]
.......F
=================================== FAILURES ===================================
_______ TestCreatePrReviewComment.test_create_pr_review_comment_failure ________

self = <stampbot.github_client.GitHubAppClient object at 0x7fd7b280bdd0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
message = 'Config error'

    def create_pr_review_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
    ) -> bool:
        """Create a comment review on a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            message: Review comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_review_comment",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               pr = repo.get_pull(pr_number)
                     ^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:706: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull' id='140564390754160'>
args = (42,), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestCreatePrReviewComment object at 0x7fd7b6ec5f90>

    def test_create_pr_review_comment_failure(self):
        """Test review comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_pull.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.create_pr_review_comment(
                123456,
                "owner/repo",
                42,
                "Config error",
            )

tests/test_github_client.py:1433: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fd7b280bdd0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
message = 'Config error'

    def create_pr_review_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
    ) -> bool:
        """Create a comment review on a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            message: Review comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_review_comment",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                pr.create_review(body=message, event="COMMENT")
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                github_api_requests_total.labels(operation="comment", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "commented"})
                set_span_ok(span)
    
                logger.info(
                    "Posted config error review on PR #%d in %s",
                    pr_number,
                    repo_full_name,
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() & start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/github_client.py:732: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreatePrReviewComment::test_create_pr_review_comment_failure - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 79 passed, 3 deselected, 1 warning in 2.33s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 17, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -784,7 +784,7 @@
 
                 issue.create_comment(message)
 
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........F
=================================== FAILURES ===================================
___________ TestCreateIssueComment.test_create_issue_comment_success ___________

self = <tests.test_github_client.TestCreateIssueComment object at 0x7f6b5d4de0d0>

    def test_create_issue_comment_success(self):
        """Test successful issue comment creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_issue = Mock()
            mock_repo = Mock()
            mock_repo.get_issue.return_value = mock_issue
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_issue_comment(
                123456,
                "owner/repo",
                42,
                "Help text",
            )
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:1487: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:32:12 [warning  ] Failed to post issue comment on #42 in owner/repo: unsupported operand type(s) for &: 'float' and 'float' extra={'repo': 'owner/repo', 'issue_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for &: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreateIssueComment::test_create_issue_comment_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 80 passed, 3 deselected, 1 warning in 2.19s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 18, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -808,7 +808,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
.........F
=================================== FAILURES ===================================
___________ TestCreateIssueComment.test_create_issue_comment_failure ___________

self = <stampbot.github_client.GitHubAppClient object at 0x7f138071ae10>
installation_id = 123456, repo_full_name = 'owner/repo', issue_number = 42
message = 'Help text'

    def create_issue_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        issue_number: int,
        message: str,
    ) -> bool:
        """Create a comment on an issue or pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            issue_number: Issue or pull request number
            message: Comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_issue_comment",
            {
                "github.repo": repo_full_name,
                "github.issue_number": issue_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               issue = repo.get_issue(issue_number)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:783: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_issue' id='139721737923152'>
args = (42,), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestCreateIssueComment object at 0x7f1384b9a210>

    def test_create_issue_comment_failure(self):
        """Test issue comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_issue.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.create_issue_comment(
                123456,
                "owner/repo",
                42,
                "Help text",
            )

tests/test_github_client.py:1523: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f138071ae10>
installation_id = 123456, repo_full_name = 'owner/repo', issue_number = 42
message = 'Help text'

    def create_issue_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        issue_number: int,
        message: str,
    ) -> bool:
        """Create a comment on an issue or pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            issue_number: Issue or pull request number
            message: Comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_issue_comment",
            {
                "github.repo": repo_full_name,
                "github.issue_number": issue_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                issue = repo.get_issue(issue_number)
    
                issue.create_comment(message)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                    duration
                )
                github_api_requests_total.labels(operation="issue_comment", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "commented"})
                set_span_ok(span)
    
                logger.info(
                    "Posted issue comment on #%d in %s",
                    issue_number,
                    repo_full_name,
                    extra={
                        "repo": repo_full_name,
                        "issue_number": issue_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() & start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/github_client.py:811: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreateIssueComment::test_create_issue_comment_failure - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 81 passed, 3 deselected, 1 warning in 2.32s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 19, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -861,7 +861,7 @@
                 repo = client.get_repo(repo_full_name)
                 repo.get_label(label_name)
 
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="success").inc()
 
........................................................................ [ 30%]
..F
=================================== FAILURES ===================================
__________________ TestRepoHasLabel.test_repo_has_label_true ___________________

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f3001d69bd0>

    def test_repo_has_label_true(self):
        """Test repo_has_label returns True when label exists."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.return_value = Mock()
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.repo_has_label(123456, "owner/repo", "autoapprove")
    
>           assert result is True
E           assert None is True

tests/test_github_client.py:1239: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:58:08 [debug    ] Could not verify label autoapprove in owner/repo: unsupported operand type(s) for &: 'float' and 'float' extra={'repo': 'owner/repo', 'label': 'autoapprove', 'installation_id': 123456, 'error': "unsupported operand type(s) for &: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_true - assert None is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 74 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 20, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -872,7 +872,7 @@
                 return True
 
             except GithubException as e:
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
...F
=================================== FAILURES ===================================
________________ TestRepoHasLabel.test_repo_has_label_not_found ________________

self = <stampbot.github_client.GitHubAppClient object at 0x7fb6184e4830>
installation_id = 123456, repo_full_name = 'owner/repo', label_name = 'missing'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               repo.get_label(label_name)

stampbot/github_client.py:862: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_label' id='140420069857264'>
args = ('missing',), kwargs = {}
effect = GithubException(404 {"message": "Not Found"})

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               github.GithubException.GithubException: 404 {"message": "Not Found"}

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: GithubException

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestRepoHasLabel object at 0x7fb61cb95d10>

    def test_repo_has_label_not_found(self):
        """Test repo_has_label returns False when label is missing."""
        from github.GithubException import GithubException
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = GithubException(404, {"message": "Not Found"}, None)
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.repo_has_label(123456, "owner/repo", "missing")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1275: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fb6184e4830>
installation_id = 123456, repo_full_name = 'owner/repo', label_name = 'missing'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                repo.get_label(label_name)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.label_found": True})
                set_span_ok(span)
                return True
    
            except GithubException as e:
>               duration = time.time() & start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/github_client.py:875: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_not_found - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 75 passed, 3 deselected, 1 warning in 2.33s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 21, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -897,7 +897,7 @@
                 return None
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
.....F
=================================== FAILURES ===================================
__________________ TestRepoHasLabel.test_repo_has_label_error __________________

self = <stampbot.github_client.GitHubAppClient object at 0x7f64edad9790>
installation_id = 123456, repo_full_name = 'owner/repo'
label_name = 'autoapprove'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               repo.get_label(label_name)

stampbot/github_client.py:862: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_label' id='140071460529088'>
args = ('autoapprove',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f64f1c60e90>

    def test_repo_has_label_error(self):
        """Test repo_has_label returns None on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.repo_has_label(123456, "owner/repo", "autoapprove")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1349: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f64edad9790>
installation_id = 123456, repo_full_name = 'owner/repo'
label_name = 'autoapprove'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                repo.get_label(label_name)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.label_found": True})
                set_span_ok(span)
                return True
    
            except GithubException as e:
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="failure").inc()
    
                if e.status == 404:
                    add_span_attributes(span, {"github.label_found": False})
                    set_span_ok(span)
                    return False
    
                set_span_error(span, e)
                logger.debug(
                    "Could not verify label %s in %s: %s",
                    label_name,
                    repo_full_name,
                    _sanitize_error(e),
                    extra={
                        "repo": repo_full_name,
                        "label": label_name,
                        "installation_id": installation_id,
                        "error": _sanitize_error(e),
                    },
                )
                return None
    
            except Exception as e:
>               duration = time.time() & start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/github_client.py:900: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_error - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 77 passed, 3 deselected, 1 warning in 2.31s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 22, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -960,7 +960,7 @@
 
                 has_permission = permission_index >= required_index
 
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
.................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_true ______________

self = <tests.test_github_client.TestUserHasPermission object at 0x7ff8dfcc16d0>

    def test_user_has_permission_true(self):
        """Test required permission satisfied returns True."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.return_value = "write"
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.user_has_permission(123456, "owner/repo", "alice", "write")
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:868: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:51:53 [warning  ] Failed to check collaborator permission for alice in owner/repo: unsupported operand type(s) for &: 'float' and 'float' extra={'repo': 'owner/repo', 'username': 'alice', 'installation_id': 123456, 'error': "unsupported operand type(s) for &: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_true - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 65 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 23, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -980,7 +980,7 @@
                 return has_permission
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
...................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_error _____________

self = <stampbot.github_client.GitHubAppClient object at 0x7fd96d43c1d0>
installation_id = 123456, repo_full_name = 'owner/repo', username = 'carol'
required_permission = 'maintain'

    def user_has_permission(
        self,
        installation_id: int,
        repo_full_name: str,
        username: str,
        required_permission: str,
    ) -> bool:
        """Check whether a user has required access to a repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            username: GitHub username to check
            required_permission: Minimum required repository permission
    
        Returns:
            True if user meets or exceeds required permission, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.get_collaborator_permission",
            {
                "github.repo": repo_full_name,
                "github.username": username,
                "github.required_permission": required_permission,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
>               permission = repo.get_collaborator_permission(username)
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:952: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_collaborator_permission' id='140571817812256'>
args = ('carol',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestUserHasPermission object at 0x7fd9716648a0>

    def test_user_has_permission_error(self):
        """Test permission check returns False on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.user_has_permission(123456, "owner/repo", "carol", "maintain")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:939: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fd96d43c1d0>
installation_id = 123456, repo_full_name = 'owner/repo', username = 'carol'
required_permission = 'maintain'

    def user_has_permission(
        self,
        installation_id: int,
        repo_full_name: str,
        username: str,
        required_permission: str,
    ) -> bool:
        """Check whether a user has required access to a repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            username: GitHub username to check
            required_permission: Minimum required repository permission
    
        Returns:
            True if user meets or exceeds required permission, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.get_collaborator_permission",
            {
                "github.repo": repo_full_name,
                "github.username": username,
                "github.required_permission": required_permission,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
                permission = repo.get_collaborator_permission(username)
                permission_order = ["none", "read", "triage", "write", "maintain", "admin"]
                try:
                    permission_index = permission_order.index(permission)
                    required_index = permission_order.index(required_permission)
                except ValueError:
                    permission_index = -1
                    required_index = 99
    
                has_permission = permission_index >= required_index
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_permission").observe(
                    duration
                )
                github_api_requests_total.labels(operation="get_permission", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span,
                    {
                        "github.permission": permission,
                        "github.has_permission": has_permission,
                    },
                )
                set_span_ok(span)
    
                return has_permission
    
            except Exception as e:
>               duration = time.time() & start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/github_client.py:983: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_error - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 67 passed, 3 deselected, 1 warning in 2.27s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 24, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1071,7 +1071,7 @@
                         )
                         continue
 
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
.....................................................................F
=================================== FAILURES ===================================
____________ TestGetUserTeamSlugs.test_get_user_team_slugs_success _____________

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7f58ddeb1950>

    def test_get_user_team_slugs_success(self):
        """Test successful team membership check."""
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            # Mock user
            mock_user = Mock()
            mock_user.login = "alice"
    
            # Mock team that has alice as member
            mock_team = Mock()
            mock_team.has_in_members.return_value = True
    
            # Mock org
            mock_org = Mock()
            mock_org.get_team_by_slug.return_value = mock_team
    
            mock_github = Mock()
            mock_github.get_organization.return_value = mock_org
            mock_github.get_user.return_value = mock_user
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_user_team_slugs(
                123456, "acme", "alice", ["release-team", "deploy-team"]
            )
    
>           assert result == ["release-team", "deploy-team"]
E           AssertionError: assert [] == ['release-tea...'deploy-team']
E             
E             Right contains 2 more items, first extra item: 'release-team'
E             
E             Full diff:
E             + []
E             - [
E             -     'release-team',
E             -     'deploy-team',
E             - ]

tests/test_github_client.py:1033: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:06:35 [debug    ] User alice is a member of team release-team extra={'org': 'acme', 'username': 'alice', 'team': 'release-team'}
2026-06-29 05:06:35 [debug    ] User alice is a member of team deploy-team extra={'org': 'acme', 'username': 'alice', 'team': 'deploy-team'}
2026-06-29 05:06:35 [warning  ] Failed to check team memberships for alice in acme: unsupported operand type(s) for &: 'float' and 'float' extra={'org': 'acme', 'username': 'alice', 'installation_id': 123456, 'error': "unsupported operand type(s) for &: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_success - AssertionError: assert [] == ['release-tea...'deploy-team']
  
  Right contains 2 more items, first extra item: 'release-team'
  
  Full diff:
  + []
  - [
  -     'release-team',
  -     'deploy-team',
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 69 passed, 3 deselected, 1 warning in 2.16s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 25, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1091,7 +1091,7 @@
                 return member_teams
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() & start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
.F
=================================== FAILURES ===================================
_______ TestGetUserTeamSlugs.test_get_user_team_slugs_general_exception ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f928c8db350>
installation_id = 123456, org_name = 'acme', username = 'alice'
allowed_teams = ['release-team']

    def get_user_team_slugs(
        self,
        installation_id: int,
        org_name: str,
        username: str,
        allowed_teams: list[str],
    ) -> list[str]:
        """Get team slugs the user is a member of from the allowed teams list.
    
        Args:
            installation_id: GitHub App installation ID
            org_name: Organization name
            username: GitHub username to check
            allowed_teams: List of team slugs to check (can be "org/team" or just "team")
    
        Returns:
            List of team slugs the user is a member of
        """
        start_time = time.time()
    
        with create_span(
            "github.get_user_team_slugs",
            {
                "github.org": org_name,
                "github.username": username,
                "github.installation_id": installation_id,
                "github.teams_to_check": len(allowed_teams),
            },
        ) as span:
            member_teams: list[str] = []
    
            try:
                client = self._get_installation_client(installation_id)
>               org = client.get_organization(org_name)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:1038: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_organization' id='140267399472064'>
args = ('acme',), kwargs = {}, effect = Exception('Network error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Network error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7f9290fcfe30>

    def test_get_user_team_slugs_general_exception(self):
        """Test team membership check with general exception."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_organization.side_effect = Exception("Network error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_user_team_slugs(123456, "acme", "alice", ["release-team"])
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1195: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f928c8db350>
installation_id = 123456, org_name = 'acme', username = 'alice'
allowed_teams = ['release-team']

    def get_user_team_slugs(
        self,
        installation_id: int,
        org_name: str,
        username: str,
        allowed_teams: list[str],
    ) -> list[str]:
        """Get team slugs the user is a member of from the allowed teams list.
    
        Args:
            installation_id: GitHub App installation ID
            org_name: Organization name
            username: GitHub username to check
            allowed_teams: List of team slugs to check (can be "org/team" or just "team")
    
        Returns:
            List of team slugs the user is a member of
        """
        start_time = time.time()
    
        with create_span(
            "github.get_user_team_slugs",
            {
                "github.org": org_name,
                "github.username": username,
                "github.installation_id": installation_id,
                "github.teams_to_check": len(allowed_teams),
            },
        ) as span:
            member_teams: list[str] = []
    
            try:
                client = self._get_installation_client(installation_id)
                org = client.get_organization(org_name)
    
                for team_ref in allowed_teams:
                    # Extract team slug (handle both "org/team" and "team" formats)
                    team_slug = team_ref.split("/")[-1] if "/" in team_ref else team_ref
    
                    try:
                        team = org.get_team_by_slug(team_slug)
                        # Check if user is a member
                        user = client.get_user(username)
                        if team.has_in_members(user):  # type: ignore[arg-type]
                            member_teams.append(team_slug)
                            logger.debug(
                                "User %s is a member of team %s",
                                username,
                                team_slug,
                                extra={
                                    "org": org_name,
                                    "username": username,
                                    "team": team_slug,
                                },
                            )
                    except GithubException as e:
                        # Team not found or no access - skip silently
                        logger.debug(
                            "Could not check team %s membership: %s",
                            team_slug,
                            e.data.get("message", str(e)) if hasattr(e, "data") else str(e),
                            extra={
                                "org": org_name,
                                "team": team_slug,
                                "username": username,
                            },
                        )
                        continue
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                    duration
                )
                github_api_requests_total.labels(operation="get_user_teams", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span,
                    {
                        "github.member_teams": len(member_teams),
                        "github.teams_checked": len(allowed_teams),
                    },
                )
                set_span_ok(span)
    
                return member_teams
    
            except Exception as e:
>               duration = time.time() & start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/github_client.py:1094: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_general_exception - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 73 passed, 3 deselected, 1 warning in 2.28s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 0, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -177,7 +177,7 @@
                     retry=retry,
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="success").inc()
 
................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_success ________

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f1a6970c2d0>

    def test_get_installation_client_success(self):
        """Test successful installation client creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client._get_installation_client(123456)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:211: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f1a654bd8d0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
                auth = self.integration.get_access_token(installation_id)
    
                # Configure retry with exponential backoff
                retry = Retry(
                    total=GITHUB_API_RETRY_TOTAL,
                    backoff_factor=GITHUB_API_RETRY_BACKOFF,
                    status_forcelist=[500, 502, 503, 504],
                    allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                )
    
                client = Github(
                    auth=Auth.Token(auth.token),
                    timeout=GITHUB_API_TIMEOUT,
                    retry=retry,
                )
    
>               duration = time.time() ^ start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/github_client.py:180: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_success - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 48 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 1, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -185,7 +185,7 @@
                 return client
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="failure").inc()
                 set_span_error(span, e)
.................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_failure ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f76c87536c0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
>               auth = self.integration.get_access_token(installation_id)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:164: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='GithubIntegration().get_access_token' id='140148100712832'>
args = (123456,), kwargs = {}, effect = Exception('Token exchange failed')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Token exchange failed

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f76c9f48410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            with pytest.raises(Exception, match="Token exchange failed"):
>               client._get_installation_client(123456)

tests/test_github_client.py:240: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f76c87536c0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
                auth = self.integration.get_access_token(installation_id)
    
                # Configure retry with exponential backoff
                retry = Retry(
                    total=GITHUB_API_RETRY_TOTAL,
                    backoff_factor=GITHUB_API_RETRY_BACKOFF,
                    status_forcelist=[500, 502, 503, 504],
                    allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                )
    
                client = Github(
                    auth=Auth.Token(auth.token),
                    timeout=GITHUB_API_TIMEOUT,
                    retry=retry,
                )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                github_api_requests_total.labels(operation="get_token", status="success").inc()
    
                set_span_ok(span)
                return client
    
            except Exception as e:
>               duration = time.time() ^ start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/github_client.py:188: TypeError

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f76c9f48410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           with pytest.raises(Exception, match="Token exchange failed"):
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           AssertionError: Regex pattern did not match.
E             Expected regex: 'Token exchange failed'
E             Actual message: "unsupported operand type(s) for ^: 'float' and 'float'"

tests/test_github_client.py:239: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_failure - AssertionError: Regex pattern did not match.
  Expected regex: 'Token exchange failed'
  Actual message: "unsupported operand type(s) for ^: 'float' and 'float'"
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 49 passed, 3 deselected, 1 warning in 2.28s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 2, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -249,7 +249,7 @@
                     event="APPROVE",
                 )
 
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="success").inc()
 
....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_success _____________________

self = <tests.test_github_client.TestApprovePR object at 0x7fb862edc7d0>

    def test_approve_pr_success(self):
        """Test successful PR approval."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.approve_pr(123456, "owner/repo", 42)
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:313: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:38:06 [error    ] Failed to approve PR #42 in owner/repo: unsupported operand type(s) for ^: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for ^: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 52 passed, 3 deselected, 1 warning in 2.10s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 3, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -269,7 +269,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="failure").inc()
 
.....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_failure _____________________

self = <stampbot.github_client.GitHubAppClient object at 0x7f0eeff06620>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
comment = 'Auto-approved by Stampbot'

    def approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str = "Auto-approved by Stampbot",
    ) -> bool:
        """Approve a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            comment: Review comment
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Create approval review
>               pr.create_review(
                    body=comment,
                    event="APPROVE",
                )

stampbot/github_client.py:247: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull().create_review' id='139702131919568'>
args = (), kwargs = {'body': 'Auto-approved by Stampbot', 'event': 'APPROVE'}
effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestApprovePR object at 0x7f0ef44dc910>

    def test_approve_pr_failure(self):
        """Test PR approval failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_pr.create_review.side_effect = Exception("API Error")
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.approve_pr(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:350: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f0eeff06620>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
comment = 'Auto-approved by Stampbot'

    def approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str = "Auto-approved by Stampbot",
    ) -> bool:
        """Approve a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            comment: Review comment
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Create approval review
                pr.create_review(
                    body=comment,
                    event="APPROVE",
                )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                github_api_requests_total.labels(operation="approve", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "approved"})
                set_span_ok(span)
    
                logger.info(
                    f"Approved PR #{pr_number} in {repo_full_name}",
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() ^ start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/github_client.py:272: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_failure - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 53 passed, 3 deselected, 1 warning in 2.26s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 4, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -318,7 +318,7 @@
                 pr = repo.get_pull(pr_number)
                 head_sha: str = pr.head.sha
 
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="success").inc()
 
......................................................F
=================================== FAILURES ===================================
________________ TestGetPRHeadSHA.test_get_pr_head_sha_success _________________

self = <tests.test_github_client.TestGetPRHeadSHA object at 0x7fbff76a8a50>

    def test_get_pr_head_sha_success(self):
        """Test successful PR head SHA lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_pr.head.sha = "current-head"
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_pr_head_sha(123456, "owner/repo", 42)
    
>           assert result == "current-head"
E           AssertionError: assert None == 'current-head'

tests/test_github_client.py:395: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:18:18 [error    ] Failed to get head SHA for PR #42 in owner/repo: unsupported operand type(s) for ^: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for ^: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetPRHeadSHA::test_get_pr_head_sha_success - AssertionError: assert None == 'current-head'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 54 passed, 3 deselected, 1 warning in 2.11s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 5, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -330,7 +330,7 @@
                 return head_sha
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="failure").inc()
 
.......................................................F
=================================== FAILURES ===================================
_________ TestGetPRHeadSHA.test_get_pr_head_sha_returns_none_on_error __________

self = <stampbot.github_client.GitHubAppClient object at 0x7f8840bd6530>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def get_pr_head_sha(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> str | None:
        """Get the current head SHA for a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Current pull request head SHA, or None on error.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_pr_head_sha",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:317: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140223176608464'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetPRHeadSHA object at 0x7f8844d40b90>

    def test_get_pr_head_sha_returns_none_on_error(self):
        """Test PR head SHA lookup returns None on API errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_pr_head_sha(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:427: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f8840bd6530>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def get_pr_head_sha(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> str | None:
        """Get the current head SHA for a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Current pull request head SHA, or None on error.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_pr_head_sha",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
                head_sha: str = pr.head.sha
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                github_api_requests_total.labels(operation="get_pull", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.head_sha": head_sha})
                set_span_ok(span)
    
                return head_sha
    
            except Exception as e:
>               duration = time.time() ^ start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/github_client.py:333: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetPRHeadSHA::test_get_pr_head_sha_returns_none_on_error - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 55 passed, 3 deselected, 1 warning in 2.26s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 6, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -390,7 +390,7 @@
                 review = pr.get_review(review_id)
                 review.dismiss(message)
 
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="success").inc()
 
........................................................F
=================================== FAILURES ===================================
______________ TestDismissApproval.test_dismiss_approval_success _______________

self = <tests.test_github_client.TestDismissApproval object at 0x7fabcdf98cd0>

    def test_dismiss_approval_success(self):
        """Test successful approval dismissal."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_review = Mock()
            mock_pr = Mock()
            mock_pr.get_review.return_value = mock_review
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.dismiss_approval(123456, "owner/repo", 42, 999)
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:473: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:42:16 [error    ] Failed to dismiss approval for PR #42 in owner/repo: unsupported operand type(s) for ^: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for ^: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestDismissApproval::test_dismiss_approval_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 56 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 7, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -411,7 +411,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="failure").inc()
 
.........................................................F
=================================== FAILURES ===================================
______________ TestDismissApproval.test_dismiss_approval_failure _______________

self = <stampbot.github_client.GitHubAppClient object at 0x7f5c1e5e3a50>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
review_id = 999, message = 'Approval dismissed by Stampbot'

    def dismiss_approval(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        review_id: int,
        message: str = "Approval dismissed by Stampbot",
    ) -> bool:
        """Dismiss a pull request approval.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            review_id: Review ID to dismiss
            message: Dismissal message
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.dismiss_approval",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.review_id": review_id,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get the review and dismiss it
                review = pr.get_review(review_id)
>               review.dismiss(message)

stampbot/github_client.py:391: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull().get_review().dismiss' id='140033621368784'>
args = ('Approval dismissed by Stampbot',), kwargs = {}
effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestDismissApproval object at 0x7f5c22820e10>

    def test_dismiss_approval_failure(self):
        """Test approval dismissal failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_review = Mock()
            mock_review.dismiss.side_effect = Exception("API Error")
            mock_pr = Mock()
            mock_pr.get_review.return_value = mock_review
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.dismiss_approval(123456, "owner/repo", 42, 999)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:512: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f5c1e5e3a50>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
review_id = 999, message = 'Approval dismissed by Stampbot'

    def dismiss_approval(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        review_id: int,
        message: str = "Approval dismissed by Stampbot",
    ) -> bool:
        """Dismiss a pull request approval.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            review_id: Review ID to dismiss
            message: Dismissal message
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.dismiss_approval",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.review_id": review_id,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get the review and dismiss it
                review = pr.get_review(review_id)
                review.dismiss(message)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                github_api_requests_total.labels(operation="dismiss", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "dismissed"})
                set_span_ok(span)
    
                logger.info(
                    f"Dismissed approval for PR #{pr_number} in {repo_full_name}",
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                        "review_id": review_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() ^ start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/github_client.py:414: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestDismissApproval::test_dismiss_approval_failure - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 57 passed, 3 deselected, 1 warning in 2.25s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 8, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -466,7 +466,7 @@
 
                 content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                 if isinstance(content, list):
-                    duration = time.time() - start_time
+                    duration = time.time() ^ start_time
                     github_api_request_duration_seconds.labels(operation="get_file").observe(
                         duration
                     )
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 9, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -475,7 +475,7 @@
                     set_span_ok(span)
                     return None
 
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="success").inc()
 
..........................................................F
=================================== FAILURES ===================================
__________________ TestGetRepoFile.test_get_repo_file_success __________________

self = <tests.test_github_client.TestGetRepoFile object at 0x7fe783104f50>

    def test_get_repo_file_success(self):
        """Test successful file retrieval."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_content = Mock()
            mock_content.decoded_content = b"file content"
            mock_repo = Mock()
            mock_repo.get_contents.return_value = mock_content
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_repo_file(123456, "owner/repo", "stampbot.toml")
    
>           assert result == "file content"
E           AssertionError: assert None == 'file content'

tests/test_github_client.py:557: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:23:19 [debug    ] Could not fetch stampbot.toml from owner/repo: unsupported operand type(s) for ^: 'float' and 'float' extra={'repo': 'owner/repo', 'file_path': 'stampbot.toml', 'installation_id': 123456}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetRepoFile::test_get_repo_file_success - AssertionError: assert None == 'file content'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 58 passed, 3 deselected, 1 warning in 2.12s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 10, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -487,7 +487,7 @@
                 return content.decoded_content.decode("utf-8")
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="not_found").inc()
 
............................................................F
=================================== FAILURES ===================================
___________ TestGetRepoFile.test_get_repo_file_returns_none_on_error ___________

self = <stampbot.github_client.GitHubAppClient object at 0x7f2ba192a740>
installation_id = 123456, repo_full_name = 'owner/repo'
file_path = 'nonexistent.toml', ref = None

    def get_repo_file(
        self,
        installation_id: int,
        repo_full_name: str,
        file_path: str,
        ref: str | None = None,
    ) -> str | None:
        """Get file content from repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            file_path: Path to file in repository
            ref: Git reference (branch, tag, commit). Defaults to default branch
    
        Returns:
            File content as string, or None if not found
        """
        start_time = time.time()
    
        with create_span(
            "github.get_file",
            {
                "github.repo": repo_full_name,
                "github.file_path": file_path,
                "github.ref": ref or "default",
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
>               content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:467: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_contents' id='139825301688672'>
args = ('nonexistent.toml',), kwargs = {'ref': None}
effect = Exception('File not found')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: File not found

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetRepoFile object at 0x7f2ba1934770>

    def test_get_repo_file_returns_none_on_error(self):
        """Test that get_repo_file returns None when file not found."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_contents.side_effect = Exception("File not found")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_repo_file(123456, "owner/repo", "nonexistent.toml")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:628: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f2ba192a740>
installation_id = 123456, repo_full_name = 'owner/repo'
file_path = 'nonexistent.toml', ref = None

    def get_repo_file(
        self,
        installation_id: int,
        repo_full_name: str,
        file_path: str,
        ref: str | None = None,
    ) -> str | None:
        """Get file content from repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            file_path: Path to file in repository
            ref: Git reference (branch, tag, commit). Defaults to default branch
    
        Returns:
            File content as string, or None if not found
        """
        start_time = time.time()
    
        with create_span(
            "github.get_file",
            {
                "github.repo": repo_full_name,
                "github.file_path": file_path,
                "github.ref": ref or "default",
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
                content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                if isinstance(content, list):
                    duration = time.time() - start_time
                    github_api_request_duration_seconds.labels(operation="get_file").observe(
                        duration
                    )
                    github_api_requests_total.labels(operation="get_file", status="not_found").inc()
                    add_span_attributes(span, {"github.result": "not_found"})
                    set_span_ok(span)
                    return None
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                github_api_requests_total.labels(operation="get_file", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "found"})
                set_span_ok(span)
    
                return content.decoded_content.decode("utf-8")
    
            except Exception as e:
>               duration = time.time() ^ start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/github_client.py:490: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetRepoFile::test_get_repo_file_returns_none_on_error - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 60 passed, 3 deselected, 1 warning in 2.27s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 11, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -546,7 +546,7 @@
                     if review.user.login == bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7f8e5e2691d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [] == [123]
E             
E             Right contains one more item: 123
E             
E             Full diff:
E             + []
E             - [
E             -     123,
E             - ]

tests/test_github_client.py:685: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:56:37 [error    ] Failed to find bot reviews for PR #42 in owner/repo: unsupported operand type(s) for ^: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for ^: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [] == [123]
  
  Right contains one more item: 123
  
  Full diff:
  + []
  - [
  -     123,
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.19s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 12, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -562,7 +562,7 @@
                 return bot_review_ids
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
..............................................................F
=================================== FAILURES ===================================
_______ TestFindBotReviews.test_find_bot_reviews_returns_empty_on_error ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f99c1510ad0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[int]:
        """Find all reviews created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            List of review IDs created by the bot
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:535: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140298350261120'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestFindBotReviews object at 0x7f99c5ad5310>

    def test_find_bot_reviews_returns_empty_on_error(self):
        """Test that find_bot_reviews returns empty list on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.find_bot_reviews(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:717: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f99c1510ad0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[int]:
        """Find all reviews created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            List of review IDs created by the bot
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get bot user via JWT-authenticated integration (installation tokens
                # cannot call GET /user, which is restricted by GitHub Apps integration)
                app_info = self.integration.get_app()
                bot_user = f"{app_info.slug}[bot]"
    
                # Find all reviews by bot that are approvals
                bot_review_ids = []
                for review in pr.get_reviews():
                    if review.user.login == bot_user and review.state == "APPROVED":
                        bot_review_ids.append(review.id)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                    duration
                )
                github_api_requests_total.labels(operation="find_reviews", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span, {"github.reviews_found": len(bot_review_ids), "github.bot_user": bot_user}
                )
                set_span_ok(span)
    
                return bot_review_ids
    
            except Exception as e:
>               duration = time.time() ^ start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/github_client.py:565: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_returns_empty_on_error - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 62 passed, 3 deselected, 1 warning in 2.30s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 13, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -634,7 +634,7 @@
                             }
                         )
 
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
...............................................................F
=================================== FAILURES ===================================
______ TestFindBotApprovalReviews.test_find_bot_approval_reviews_success _______

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7f6129c81450>

    def test_find_bot_approval_reviews_success(self):
        """Test successful bot approval review state lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            bot_approved_review = Mock()
            bot_approved_review.user.login = "stampbot[bot]"
            bot_approved_review.state = "APPROVED"
            bot_approved_review.id = 123
            bot_approved_review.commit_id = "headsha"
    
            bot_dismissed_review = Mock()
            bot_dismissed_review.user.login = "stampbot[bot]"
            bot_dismissed_review.state = "DISMISSED"
            bot_dismissed_review.id = 124
            bot_dismissed_review.commit_id = "oldsha"
    
            bot_commented_review = Mock()
            bot_commented_review.user.login = "stampbot[bot]"
            bot_commented_review.state = "COMMENTED"
            bot_commented_review.id = 125
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [
                bot_approved_review,
                bot_dismissed_review,
                bot_commented_review,
                other_review,
            ]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
    
>           assert result == [
                {"id": 123, "state": "APPROVED", "commit_id": "headsha"},
                {"id": 124, "state": "DISMISSED", "commit_id": "oldsha"},
            ]
E           AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
E             
E             Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
E             
E             Full diff:
E             + []
E             - [
E             -     {
E             -         'commit_id': 'headsha',
E             -         'id': 123,
E             -         'state': 'APPROVED',
E             -     },
E             -     {
E             -         'commit_id': 'oldsha',
E             -         'id': 124,
E             -         'state': 'DISMISSED',
E             -     },
E             - ]

tests/test_github_client.py:790: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:12:45 [error    ] Failed to find bot approval reviews for PR #42 in owner/repo: unsupported operand type(s) for ^: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for ^: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_success - AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
  
  Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
  
  Full diff:
  + []
  - [
  -     {
  -         'commit_id': 'headsha',
  -         'id': 123,
  -         'state': 'APPROVED',
  -     },
  -     {
  -         'commit_id': 'oldsha',
  -         'id': 124,
  -         'state': 'DISMISSED',
  -     },
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 63 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 14, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -650,7 +650,7 @@
                 return bot_reviews
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
                 )
................................................................F
=================================== FAILURES ===================================
_ TestFindBotApprovalReviews.test_find_bot_approval_reviews_returns_empty_on_error _

self = <stampbot.github_client.GitHubAppClient object at 0x7fe9bba9bd10>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_approval_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[BotReview]:
        """Find approval review states created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Review state details for bot approval reviews.
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_approval_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:615: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140641852509552'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7fe9bfd71590>

    def test_find_bot_approval_reviews_returns_empty_on_error(self):
        """Test that find_bot_approval_reviews returns empty list on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:825: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fe9bba9bd10>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_approval_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[BotReview]:
        """Find approval review states created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Review state details for bot approval reviews.
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_approval_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get bot user via JWT-authenticated integration (installation tokens
                # cannot call GET /user, which is restricted by GitHub Apps integration)
                app_info = self.integration.get_app()
                bot_user = f"{app_info.slug}[bot]"
    
                bot_reviews: list[BotReview] = []
                for review in pr.get_reviews():
                    if review.user.login == bot_user and review.state in (
                        "APPROVED",
                        "DISMISSED",
                    ):
                        bot_reviews.append(
                            {
                                "id": review.id,
                                "state": review.state,
                                "commit_id": getattr(review, "commit_id", None),
                            }
                        )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                    duration
                )
                github_api_requests_total.labels(operation="find_reviews", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span, {"github.reviews_found": len(bot_reviews), "github.bot_user": bot_user}
                )
                set_span_ok(span)
    
                return bot_reviews
    
            except Exception as e:
>               duration = time.time() ^ start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/github_client.py:653: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_returns_empty_on_error - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 64 passed, 3 deselected, 1 warning in 2.28s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 15, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -707,7 +707,7 @@
 
                 pr.create_review(body=message, event="COMMENT")
 
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="success").inc()
 
........................................................................ [ 30%]
......F
=================================== FAILURES ===================================
_______ TestCreatePrReviewComment.test_create_pr_review_comment_success ________

self = <tests.test_github_client.TestCreatePrReviewComment object at 0x7f4a661e9e50>

    def test_create_pr_review_comment_success(self):
        """Test successful review comment creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_pr_review_comment(
                123456,
                "owner/repo",
                42,
                "Config error",
            )
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:1398: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:25:30 [warning  ] Failed to post config error review for PR #42 in owner/repo: unsupported operand type(s) for ^: 'float' and 'float' extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for ^: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreatePrReviewComment::test_create_pr_review_comment_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 78 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 16, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -729,7 +729,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="failure").inc()
 
........................................................................ [ 30%]
.......F
=================================== FAILURES ===================================
_______ TestCreatePrReviewComment.test_create_pr_review_comment_failure ________

self = <stampbot.github_client.GitHubAppClient object at 0x7efd8d108350>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
message = 'Config error'

    def create_pr_review_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
    ) -> bool:
        """Create a comment review on a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            message: Review comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_review_comment",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               pr = repo.get_pull(pr_number)
                     ^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:706: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull' id='139627459737456'>
args = (42,), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestCreatePrReviewComment object at 0x7efd915cdf90>

    def test_create_pr_review_comment_failure(self):
        """Test review comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_pull.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.create_pr_review_comment(
                123456,
                "owner/repo",
                42,
                "Config error",
            )

tests/test_github_client.py:1433: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7efd8d108350>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
message = 'Config error'

    def create_pr_review_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
    ) -> bool:
        """Create a comment review on a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            message: Review comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_review_comment",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                pr.create_review(body=message, event="COMMENT")
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                github_api_requests_total.labels(operation="comment", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "commented"})
                set_span_ok(span)
    
                logger.info(
                    "Posted config error review on PR #%d in %s",
                    pr_number,
                    repo_full_name,
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() ^ start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/github_client.py:732: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreatePrReviewComment::test_create_pr_review_comment_failure - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 79 passed, 3 deselected, 1 warning in 2.33s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 17, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -784,7 +784,7 @@
 
                 issue.create_comment(message)
 
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
........F
=================================== FAILURES ===================================
___________ TestCreateIssueComment.test_create_issue_comment_success ___________

self = <tests.test_github_client.TestCreateIssueComment object at 0x7f603e2120d0>

    def test_create_issue_comment_success(self):
        """Test successful issue comment creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_issue = Mock()
            mock_repo = Mock()
            mock_repo.get_issue.return_value = mock_issue
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_issue_comment(
                123456,
                "owner/repo",
                42,
                "Help text",
            )
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:1487: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:51:19 [warning  ] Failed to post issue comment on #42 in owner/repo: unsupported operand type(s) for ^: 'float' and 'float' extra={'repo': 'owner/repo', 'issue_number': 42, 'installation_id': 123456, 'error': "unsupported operand type(s) for ^: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreateIssueComment::test_create_issue_comment_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 80 passed, 3 deselected, 1 warning in 2.19s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 18, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -808,7 +808,7 @@
                 return True
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
                 )
........................................................................ [ 30%]
.........F
=================================== FAILURES ===================================
___________ TestCreateIssueComment.test_create_issue_comment_failure ___________

self = <stampbot.github_client.GitHubAppClient object at 0x7f822f32c050>
installation_id = 123456, repo_full_name = 'owner/repo', issue_number = 42
message = 'Help text'

    def create_issue_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        issue_number: int,
        message: str,
    ) -> bool:
        """Create a comment on an issue or pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            issue_number: Issue or pull request number
            message: Comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_issue_comment",
            {
                "github.repo": repo_full_name,
                "github.issue_number": issue_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               issue = repo.get_issue(issue_number)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:783: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_issue' id='140197116226128'>
args = (42,), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestCreateIssueComment object at 0x7f82339c6210>

    def test_create_issue_comment_failure(self):
        """Test issue comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_issue.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.create_issue_comment(
                123456,
                "owner/repo",
                42,
                "Help text",
            )

tests/test_github_client.py:1523: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f822f32c050>
installation_id = 123456, repo_full_name = 'owner/repo', issue_number = 42
message = 'Help text'

    def create_issue_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        issue_number: int,
        message: str,
    ) -> bool:
        """Create a comment on an issue or pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            issue_number: Issue or pull request number
            message: Comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_issue_comment",
            {
                "github.repo": repo_full_name,
                "github.issue_number": issue_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                issue = repo.get_issue(issue_number)
    
                issue.create_comment(message)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                    duration
                )
                github_api_requests_total.labels(operation="issue_comment", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "commented"})
                set_span_ok(span)
    
                logger.info(
                    "Posted issue comment on #%d in %s",
                    issue_number,
                    repo_full_name,
                    extra={
                        "repo": repo_full_name,
                        "issue_number": issue_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
            except Exception as e:
>               duration = time.time() ^ start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/github_client.py:811: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreateIssueComment::test_create_issue_comment_failure - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 81 passed, 3 deselected, 1 warning in 2.33s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 19, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -861,7 +861,7 @@
                 repo = client.get_repo(repo_full_name)
                 repo.get_label(label_name)
 
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="success").inc()
 
........................................................................ [ 30%]
..F
=================================== FAILURES ===================================
__________________ TestRepoHasLabel.test_repo_has_label_true ___________________

self = <tests.test_github_client.TestRepoHasLabel object at 0x7fea8640dbd0>

    def test_repo_has_label_true(self):
        """Test repo_has_label returns True when label exists."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.return_value = Mock()
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.repo_has_label(123456, "owner/repo", "autoapprove")
    
>           assert result is True
E           assert None is True

tests/test_github_client.py:1239: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:15:22 [debug    ] Could not verify label autoapprove in owner/repo: unsupported operand type(s) for ^: 'float' and 'float' extra={'repo': 'owner/repo', 'label': 'autoapprove', 'installation_id': 123456, 'error': "unsupported operand type(s) for ^: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_true - assert None is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 74 passed, 3 deselected, 1 warning in 2.18s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 20, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -872,7 +872,7 @@
                 return True
 
             except GithubException as e:
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
...F
=================================== FAILURES ===================================
________________ TestRepoHasLabel.test_repo_has_label_not_found ________________

self = <stampbot.github_client.GitHubAppClient object at 0x7fd930b14290>
installation_id = 123456, repo_full_name = 'owner/repo', label_name = 'missing'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               repo.get_label(label_name)

stampbot/github_client.py:862: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_label' id='140570802837488'>
args = ('missing',), kwargs = {}
effect = GithubException(404 {"message": "Not Found"})

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               github.GithubException.GithubException: 404 {"message": "Not Found"}

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: GithubException

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestRepoHasLabel object at 0x7fd9351e9d10>

    def test_repo_has_label_not_found(self):
        """Test repo_has_label returns False when label is missing."""
        from github.GithubException import GithubException
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = GithubException(404, {"message": "Not Found"}, None)
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.repo_has_label(123456, "owner/repo", "missing")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1275: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fd930b14290>
installation_id = 123456, repo_full_name = 'owner/repo', label_name = 'missing'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                repo.get_label(label_name)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.label_found": True})
                set_span_ok(span)
                return True
    
            except GithubException as e:
>               duration = time.time() ^ start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/github_client.py:875: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_not_found - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 75 passed, 3 deselected, 1 warning in 2.30s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 21, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -897,7 +897,7 @@
                 return None
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
........................................................................ [ 30%]
.....F
=================================== FAILURES ===================================
__________________ TestRepoHasLabel.test_repo_has_label_error __________________

self = <stampbot.github_client.GitHubAppClient object at 0x7ff2ba2ba990>
installation_id = 123456, repo_full_name = 'owner/repo'
label_name = 'autoapprove'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               repo.get_label(label_name)

stampbot/github_client.py:862: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_label' id='140680481727424'>
args = ('autoapprove',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestRepoHasLabel object at 0x7ff2be4f8e90>

    def test_repo_has_label_error(self):
        """Test repo_has_label returns None on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.repo_has_label(123456, "owner/repo", "autoapprove")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1349: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7ff2ba2ba990>
installation_id = 123456, repo_full_name = 'owner/repo'
label_name = 'autoapprove'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                repo.get_label(label_name)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.label_found": True})
                set_span_ok(span)
                return True
    
            except GithubException as e:
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="failure").inc()
    
                if e.status == 404:
                    add_span_attributes(span, {"github.label_found": False})
                    set_span_ok(span)
                    return False
    
                set_span_error(span, e)
                logger.debug(
                    "Could not verify label %s in %s: %s",
                    label_name,
                    repo_full_name,
                    _sanitize_error(e),
                    extra={
                        "repo": repo_full_name,
                        "label": label_name,
                        "installation_id": installation_id,
                        "error": _sanitize_error(e),
                    },
                )
                return None
    
            except Exception as e:
>               duration = time.time() ^ start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/github_client.py:900: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_error - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 77 passed, 3 deselected, 1 warning in 2.32s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 22, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -960,7 +960,7 @@
 
                 has_permission = permission_index >= required_index
 
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
.................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_true ______________

self = <tests.test_github_client.TestUserHasPermission object at 0x7f636b2116d0>

    def test_user_has_permission_true(self):
        """Test required permission satisfied returns True."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.return_value = "write"
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.user_has_permission(123456, "owner/repo", "alice", "write")
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:868: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:23:03 [warning  ] Failed to check collaborator permission for alice in owner/repo: unsupported operand type(s) for ^: 'float' and 'float' extra={'repo': 'owner/repo', 'username': 'alice', 'installation_id': 123456, 'error': "unsupported operand type(s) for ^: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_true - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 65 passed, 3 deselected, 1 warning in 2.16s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 23, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -980,7 +980,7 @@
                 return has_permission
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
                 )
...................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_error _____________

self = <stampbot.github_client.GitHubAppClient object at 0x7f84d7914350>
installation_id = 123456, repo_full_name = 'owner/repo', username = 'carol'
required_permission = 'maintain'

    def user_has_permission(
        self,
        installation_id: int,
        repo_full_name: str,
        username: str,
        required_permission: str,
    ) -> bool:
        """Check whether a user has required access to a repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            username: GitHub username to check
            required_permission: Minimum required repository permission
    
        Returns:
            True if user meets or exceeds required permission, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.get_collaborator_permission",
            {
                "github.repo": repo_full_name,
                "github.username": username,
                "github.required_permission": required_permission,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
>               permission = repo.get_collaborator_permission(username)
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:952: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_collaborator_permission' id='140208529056032'>
args = ('carol',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestUserHasPermission object at 0x7f84dbb548a0>

    def test_user_has_permission_error(self):
        """Test permission check returns False on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.user_has_permission(123456, "owner/repo", "carol", "maintain")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:939: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f84d7914350>
installation_id = 123456, repo_full_name = 'owner/repo', username = 'carol'
required_permission = 'maintain'

    def user_has_permission(
        self,
        installation_id: int,
        repo_full_name: str,
        username: str,
        required_permission: str,
    ) -> bool:
        """Check whether a user has required access to a repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            username: GitHub username to check
            required_permission: Minimum required repository permission
    
        Returns:
            True if user meets or exceeds required permission, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.get_collaborator_permission",
            {
                "github.repo": repo_full_name,
                "github.username": username,
                "github.required_permission": required_permission,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
                permission = repo.get_collaborator_permission(username)
                permission_order = ["none", "read", "triage", "write", "maintain", "admin"]
                try:
                    permission_index = permission_order.index(permission)
                    required_index = permission_order.index(required_permission)
                except ValueError:
                    permission_index = -1
                    required_index = 99
    
                has_permission = permission_index >= required_index
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_permission").observe(
                    duration
                )
                github_api_requests_total.labels(operation="get_permission", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span,
                    {
                        "github.permission": permission,
                        "github.has_permission": has_permission,
                    },
                )
                set_span_ok(span)
    
                return has_permission
    
            except Exception as e:
>               duration = time.time() ^ start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/github_client.py:983: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_error - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 67 passed, 3 deselected, 1 warning in 2.27s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 24, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1071,7 +1071,7 @@
                         )
                         continue
 
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
.....................................................................F
=================================== FAILURES ===================================
____________ TestGetUserTeamSlugs.test_get_user_team_slugs_success _____________

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7f00f33ed950>

    def test_get_user_team_slugs_success(self):
        """Test successful team membership check."""
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            # Mock user
            mock_user = Mock()
            mock_user.login = "alice"
    
            # Mock team that has alice as member
            mock_team = Mock()
            mock_team.has_in_members.return_value = True
    
            # Mock org
            mock_org = Mock()
            mock_org.get_team_by_slug.return_value = mock_team
    
            mock_github = Mock()
            mock_github.get_organization.return_value = mock_org
            mock_github.get_user.return_value = mock_user
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_user_team_slugs(
                123456, "acme", "alice", ["release-team", "deploy-team"]
            )
    
>           assert result == ["release-team", "deploy-team"]
E           AssertionError: assert [] == ['release-tea...'deploy-team']
E             
E             Right contains 2 more items, first extra item: 'release-team'
E             
E             Full diff:
E             + []
E             - [
E             -     'release-team',
E             -     'deploy-team',
E             - ]

tests/test_github_client.py:1033: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:59:03 [debug    ] User alice is a member of team release-team extra={'org': 'acme', 'username': 'alice', 'team': 'release-team'}
2026-06-29 04:59:03 [debug    ] User alice is a member of team deploy-team extra={'org': 'acme', 'username': 'alice', 'team': 'deploy-team'}
2026-06-29 04:59:03 [warning  ] Failed to check team memberships for alice in acme: unsupported operand type(s) for ^: 'float' and 'float' extra={'org': 'acme', 'username': 'alice', 'installation_id': 123456, 'error': "unsupported operand type(s) for ^: 'float' and 'float'"}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_success - AssertionError: assert [] == ['release-tea...'deploy-team']
  
  Right contains 2 more items, first extra item: 'release-team'
  
  Full diff:
  + []
  - [
  -     'release-team',
  -     'deploy-team',
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 69 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 25, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1091,7 +1091,7 @@
                 return member_teams
 
             except Exception as e:
-                duration = time.time() - start_time
+                duration = time.time() ^ start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
                 )
........................................................................ [ 30%]
.F
=================================== FAILURES ===================================
_______ TestGetUserTeamSlugs.test_get_user_team_slugs_general_exception ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f88af9ac230>
installation_id = 123456, org_name = 'acme', username = 'alice'
allowed_teams = ['release-team']

    def get_user_team_slugs(
        self,
        installation_id: int,
        org_name: str,
        username: str,
        allowed_teams: list[str],
    ) -> list[str]:
        """Get team slugs the user is a member of from the allowed teams list.
    
        Args:
            installation_id: GitHub App installation ID
            org_name: Organization name
            username: GitHub username to check
            allowed_teams: List of team slugs to check (can be "org/team" or just "team")
    
        Returns:
            List of team slugs the user is a member of
        """
        start_time = time.time()
    
        with create_span(
            "github.get_user_team_slugs",
            {
                "github.org": org_name,
                "github.username": username,
                "github.installation_id": installation_id,
                "github.teams_to_check": len(allowed_teams),
            },
        ) as span:
            member_teams: list[str] = []
    
            try:
                client = self._get_installation_client(installation_id)
>               org = client.get_organization(org_name)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:1038: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_organization' id='140225037820864'>
args = ('acme',), kwargs = {}, effect = Exception('Network error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Network error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7f88b3fcbe30>

    def test_get_user_team_slugs_general_exception(self):
        """Test team membership check with general exception."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_organization.side_effect = Exception("Network error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_user_team_slugs(123456, "acme", "alice", ["release-team"])
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1195: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f88af9ac230>
installation_id = 123456, org_name = 'acme', username = 'alice'
allowed_teams = ['release-team']

    def get_user_team_slugs(
        self,
        installation_id: int,
        org_name: str,
        username: str,
        allowed_teams: list[str],
    ) -> list[str]:
        """Get team slugs the user is a member of from the allowed teams list.
    
        Args:
            installation_id: GitHub App installation ID
            org_name: Organization name
            username: GitHub username to check
            allowed_teams: List of team slugs to check (can be "org/team" or just "team")
    
        Returns:
            List of team slugs the user is a member of
        """
        start_time = time.time()
    
        with create_span(
            "github.get_user_team_slugs",
            {
                "github.org": org_name,
                "github.username": username,
                "github.installation_id": installation_id,
                "github.teams_to_check": len(allowed_teams),
            },
        ) as span:
            member_teams: list[str] = []
    
            try:
                client = self._get_installation_client(installation_id)
                org = client.get_organization(org_name)
    
                for team_ref in allowed_teams:
                    # Extract team slug (handle both "org/team" and "team" formats)
                    team_slug = team_ref.split("/")[-1] if "/" in team_ref else team_ref
    
                    try:
                        team = org.get_team_by_slug(team_slug)
                        # Check if user is a member
                        user = client.get_user(username)
                        if team.has_in_members(user):  # type: ignore[arg-type]
                            member_teams.append(team_slug)
                            logger.debug(
                                "User %s is a member of team %s",
                                username,
                                team_slug,
                                extra={
                                    "org": org_name,
                                    "username": username,
                                    "team": team_slug,
                                },
                            )
                    except GithubException as e:
                        # Team not found or no access - skip silently
                        logger.debug(
                            "Could not check team %s membership: %s",
                            team_slug,
                            e.data.get("message", str(e)) if hasattr(e, "data") else str(e),
                            extra={
                                "org": org_name,
                                "team": team_slug,
                                "username": username,
                            },
                        )
                        continue
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                    duration
                )
                github_api_requests_total.labels(operation="get_user_teams", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span,
                    {
                        "github.member_teams": len(member_teams),
                        "github.teams_checked": len(allowed_teams),
                    },
                )
                set_span_ok(span)
    
                return member_teams
    
            except Exception as e:
>               duration = time.time() ^ start_time
                           ^^^^^^^^^^^^^^^^^^^^^^^^
E               TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/github_client.py:1094: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_general_exception - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 73 passed, 3 deselected, 1 warning in 2.30s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 0, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if review.user.login != bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7f148ff891d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [456] == [123]
E             
E             At index 0 diff: 456 != 123
E             
E             Full diff:
E               [
E             -     123,
E             +     456,
E               ]

tests/test_github_client.py:685: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [456] == [123]
  
  At index 0 diff: 456 != 123
  
  Full diff:
    [
  -     123,
  +     456,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 1, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if review.user.login == bot_user and review.state != "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7fa2dad111d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [] == [123]
E             
E             Right contains one more item: 123
E             
E             Full diff:
E             + []
E             - [
E             -     123,
E             - ]

tests/test_github_client.py:685: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [] == [123]
  
  Right contains one more item: 123
  
  Full diff:
  + []
  - [
  -     123,
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.13s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 2, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -622,7 +622,7 @@
 
                 bot_reviews: list[BotReview] = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state in (
+                    if review.user.login != bot_user and review.state in (
                         "APPROVED",
                         "DISMISSED",
                     ):
...............................................................F
=================================== FAILURES ===================================
______ TestFindBotApprovalReviews.test_find_bot_approval_reviews_success _______

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7f9288b55450>

    def test_find_bot_approval_reviews_success(self):
        """Test successful bot approval review state lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            bot_approved_review = Mock()
            bot_approved_review.user.login = "stampbot[bot]"
            bot_approved_review.state = "APPROVED"
            bot_approved_review.id = 123
            bot_approved_review.commit_id = "headsha"
    
            bot_dismissed_review = Mock()
            bot_dismissed_review.user.login = "stampbot[bot]"
            bot_dismissed_review.state = "DISMISSED"
            bot_dismissed_review.id = 124
            bot_dismissed_review.commit_id = "oldsha"
    
            bot_commented_review = Mock()
            bot_commented_review.user.login = "stampbot[bot]"
            bot_commented_review.state = "COMMENTED"
            bot_commented_review.id = 125
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [
                bot_approved_review,
                bot_dismissed_review,
                bot_commented_review,
                other_review,
            ]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
    
>           assert result == [
                {"id": 123, "state": "APPROVED", "commit_id": "headsha"},
                {"id": 124, "state": "DISMISSED", "commit_id": "oldsha"},
            ]
E           AssertionError: assert [{'commit_id'...: 'APPROVED'}] == [{'commit_id'... 'DISMISSED'}]
E             
E             At index 0 diff: {'id': 456, 'state': 'APPROVED', 'commit_id': <Mock name='mock.commit_id' id='140267262328912'>} != {'id': 123, 'state': 'APPROVED', 'commit_id': 'headsha'}
E             Right contains one more item: {'commit_id': 'oldsha', 'id': 124, 'state': 'DISMISSED'}
E             
E             Full diff:
E               [
E                   {
E             -         'commit_id': 'headsha',
E             +         'commit_id': <Mock name='mock.commit_id' id='140267262328912'>,
E             -         'id': 123,
E             ?               ^^^
E             +         'id': 456,
E             ?               ^^^
E                       'state': 'APPROVED',
E                   },
E             -     {
E             -         'commit_id': 'oldsha',
E             -         'id': 124,
E             -         'state': 'DISMISSED',
E             -     },
E               ]

tests/test_github_client.py:790: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_success - AssertionError: assert [{'commit_id'...: 'APPROVED'}] == [{'commit_id'... 'DISMISSED'}]
  
  At index 0 diff: {'id': 456, 'state': 'APPROVED', 'commit_id': <Mock name='mock.commit_id' id='140267262328912'>} != {'id': 123, 'state': 'APPROVED', 'commit_id': 'headsha'}
  Right contains one more item: {'commit_id': 'oldsha', 'id': 124, 'state': 'DISMISSED'}
  
  Full diff:
    [
        {
  -         'commit_id': 'headsha',
  +         'commit_id': <Mock name='mock.commit_id' id='140267262328912'>,
  -         'id': 123,
  ?               ^^^
  +         'id': 456,
  ?               ^^^
            'state': 'APPROVED',
        },
  -     {
  -         'commit_id': 'oldsha',
  -         'id': 124,
  -         'state': 'DISMISSED',
  -     },
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 63 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 3, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -876,7 +876,7 @@
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
-                if e.status == 404:
+                if e.status != 404:
                     add_span_attributes(span, {"github.label_found": False})
                     set_span_ok(span)
                     return False
........................................................................ [ 30%]
...F
=================================== FAILURES ===================================
________________ TestRepoHasLabel.test_repo_has_label_not_found ________________

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f92c4781d10>

    def test_repo_has_label_not_found(self):
        """Test repo_has_label returns False when label is missing."""
        from github.GithubException import GithubException
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = GithubException(404, {"message": "Not Found"}, None)
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.repo_has_label(123456, "owner/repo", "missing")
    
>           assert result is False
E           assert None is False

tests/test_github_client.py:1277: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:20:35 [debug    ] Could not verify label missing in owner/repo: 404 {"message": "Not Found"} extra={'repo': 'owner/repo', 'label': 'missing', 'installation_id': 123456, 'error': '404 {"message": "Not Found"}'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_not_found - assert None is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 75 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 0, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if review.user.login < bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7fb0f0c111d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [456] == [123]
E             
E             At index 0 diff: 456 != 123
E             
E             Full diff:
E               [
E             -     123,
E             +     456,
E               ]

tests/test_github_client.py:685: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [456] == [123]
  
  At index 0 diff: 456 != 123
  
  Full diff:
    [
  -     123,
  +     456,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 1, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if review.user.login == bot_user and review.state < "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7ff98ced11d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [] == [123]
E             
E             Right contains one more item: 123
E             
E             Full diff:
E             + []
E             - [
E             -     123,
E             - ]

tests/test_github_client.py:685: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [] == [123]
  
  Right contains one more item: 123
  
  Full diff:
  + []
  - [
  -     123,
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.13s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 2, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -622,7 +622,7 @@
 
                 bot_reviews: list[BotReview] = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state in (
+                    if review.user.login < bot_user and review.state in (
                         "APPROVED",
                         "DISMISSED",
                     ):
...............................................................F
=================================== FAILURES ===================================
______ TestFindBotApprovalReviews.test_find_bot_approval_reviews_success _______

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7f70e216d450>

    def test_find_bot_approval_reviews_success(self):
        """Test successful bot approval review state lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            bot_approved_review = Mock()
            bot_approved_review.user.login = "stampbot[bot]"
            bot_approved_review.state = "APPROVED"
            bot_approved_review.id = 123
            bot_approved_review.commit_id = "headsha"
    
            bot_dismissed_review = Mock()
            bot_dismissed_review.user.login = "stampbot[bot]"
            bot_dismissed_review.state = "DISMISSED"
            bot_dismissed_review.id = 124
            bot_dismissed_review.commit_id = "oldsha"
    
            bot_commented_review = Mock()
            bot_commented_review.user.login = "stampbot[bot]"
            bot_commented_review.state = "COMMENTED"
            bot_commented_review.id = 125
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [
                bot_approved_review,
                bot_dismissed_review,
                bot_commented_review,
                other_review,
            ]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
    
>           assert result == [
                {"id": 123, "state": "APPROVED", "commit_id": "headsha"},
                {"id": 124, "state": "DISMISSED", "commit_id": "oldsha"},
            ]
E           AssertionError: assert [{'commit_id'...: 'APPROVED'}] == [{'commit_id'... 'DISMISSED'}]
E             
E             At index 0 diff: {'id': 456, 'state': 'APPROVED', 'commit_id': <Mock name='mock.commit_id' id='140122735919184'>} != {'id': 123, 'state': 'APPROVED', 'commit_id': 'headsha'}
E             Right contains one more item: {'commit_id': 'oldsha', 'id': 124, 'state': 'DISMISSED'}
E             
E             Full diff:
E               [
E                   {
E             -         'commit_id': 'headsha',
E             +         'commit_id': <Mock name='mock.commit_id' id='140122735919184'>,
E             -         'id': 123,
E             ?               ^^^
E             +         'id': 456,
E             ?               ^^^
E                       'state': 'APPROVED',
E                   },
E             -     {
E             -         'commit_id': 'oldsha',
E             -         'id': 124,
E             -         'state': 'DISMISSED',
E             -     },
E               ]

tests/test_github_client.py:790: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_success - AssertionError: assert [{'commit_id'...: 'APPROVED'}] == [{'commit_id'... 'DISMISSED'}]
  
  At index 0 diff: {'id': 456, 'state': 'APPROVED', 'commit_id': <Mock name='mock.commit_id' id='140122735919184'>} != {'id': 123, 'state': 'APPROVED', 'commit_id': 'headsha'}
  Right contains one more item: {'commit_id': 'oldsha', 'id': 124, 'state': 'DISMISSED'}
  
  Full diff:
    [
        {
  -         'commit_id': 'headsha',
  +         'commit_id': <Mock name='mock.commit_id' id='140122735919184'>,
  -         'id': 123,
  ?               ^^^
  +         'id': 456,
  ?               ^^^
            'state': 'APPROVED',
        },
  -     {
  -         'commit_id': 'oldsha',
  -         'id': 124,
  -         'state': 'DISMISSED',
  -     },
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 63 passed, 3 deselected, 1 warning in 2.13s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 3, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -876,7 +876,7 @@
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
-                if e.status == 404:
+                if e.status < 404:
                     add_span_attributes(span, {"github.label_found": False})
                     set_span_ok(span)
                     return False
........................................................................ [ 30%]
...F
=================================== FAILURES ===================================
________________ TestRepoHasLabel.test_repo_has_label_not_found ________________

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f2a21d5dd10>

    def test_repo_has_label_not_found(self):
        """Test repo_has_label returns False when label is missing."""
        from github.GithubException import GithubException
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = GithubException(404, {"message": "Not Found"}, None)
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.repo_has_label(123456, "owner/repo", "missing")
    
>           assert result is False
E           assert None is False

tests/test_github_client.py:1277: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:34:49 [debug    ] Could not verify label missing in owner/repo: 404 {"message": "Not Found"} extra={'repo': 'owner/repo', 'label': 'missing', 'installation_id': 123456, 'error': '404 {"message": "Not Found"}'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_not_found - assert None is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 75 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 0, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if review.user.login <= bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7f9521e091d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [123, 456] == [123]
E             
E             Left contains one more item: 456
E             
E             Full diff:
E               [
E                   123,
E             +     456,
E               ]

tests/test_github_client.py:685: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [123, 456] == [123]
  
  Left contains one more item: 456
  
  Full diff:
    [
        123,
  +     456,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.16s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 1, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if review.user.login == bot_user and review.state <= "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 2, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -622,7 +622,7 @@
 
                 bot_reviews: list[BotReview] = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state in (
+                    if review.user.login <= bot_user and review.state in (
                         "APPROVED",
                         "DISMISSED",
                     ):
...............................................................F
=================================== FAILURES ===================================
______ TestFindBotApprovalReviews.test_find_bot_approval_reviews_success _______

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7faba1bb9450>

    def test_find_bot_approval_reviews_success(self):
        """Test successful bot approval review state lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            bot_approved_review = Mock()
            bot_approved_review.user.login = "stampbot[bot]"
            bot_approved_review.state = "APPROVED"
            bot_approved_review.id = 123
            bot_approved_review.commit_id = "headsha"
    
            bot_dismissed_review = Mock()
            bot_dismissed_review.user.login = "stampbot[bot]"
            bot_dismissed_review.state = "DISMISSED"
            bot_dismissed_review.id = 124
            bot_dismissed_review.commit_id = "oldsha"
    
            bot_commented_review = Mock()
            bot_commented_review.user.login = "stampbot[bot]"
            bot_commented_review.state = "COMMENTED"
            bot_commented_review.id = 125
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [
                bot_approved_review,
                bot_dismissed_review,
                bot_commented_review,
                other_review,
            ]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
    
>           assert result == [
                {"id": 123, "state": "APPROVED", "commit_id": "headsha"},
                {"id": 124, "state": "DISMISSED", "commit_id": "oldsha"},
            ]
E           AssertionError: assert [{'commit_id'...: 'APPROVED'}] == [{'commit_id'... 'DISMISSED'}]
E             
E             Left contains one more item: {'commit_id': <Mock name='mock.commit_id' id='140375056990288'>, 'id': 456, 'state': 'APPROVED'}
E             
E             Full diff:
E               [
E                   {
E                       'commit_id': 'headsha',
E                       'id': 123,
E                       'state': 'APPROVED',
E                   },
E                   {
E                       'commit_id': 'oldsha',
E                       'id': 124,
E                       'state': 'DISMISSED',
E                   },
E             +     {
E             +         'commit_id': <Mock name='mock.commit_id' id='140375056990288'>,
E             +         'id': 456,
E             +         'state': 'APPROVED',
E             +     },
E               ]

tests/test_github_client.py:790: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_success - AssertionError: assert [{'commit_id'...: 'APPROVED'}] == [{'commit_id'... 'DISMISSED'}]
  
  Left contains one more item: {'commit_id': <Mock name='mock.commit_id' id='140375056990288'>, 'id': 456, 'state': 'APPROVED'}
  
  Full diff:
    [
        {
            'commit_id': 'headsha',
            'id': 123,
            'state': 'APPROVED',
        },
        {
            'commit_id': 'oldsha',
            'id': 124,
            'state': 'DISMISSED',
        },
  +     {
  +         'commit_id': <Mock name='mock.commit_id' id='140375056990288'>,
  +         'id': 456,
  +         'state': 'APPROVED',
  +     },
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 63 passed, 3 deselected, 1 warning in 2.13s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 3, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -876,7 +876,7 @@
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
-                if e.status == 404:
+                if e.status <= 404:
                     add_span_attributes(span, {"github.label_found": False})
                     set_span_ok(span)
                     return False
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 0, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if review.user.login > bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7f9dd7ec91d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [] == [123]
E             
E             Right contains one more item: 123
E             
E             Full diff:
E             + []
E             - [
E             -     123,
E             - ]

tests/test_github_client.py:685: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [] == [123]
  
  Right contains one more item: 123
  
  Full diff:
  + []
  - [
  -     123,
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 1, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if review.user.login == bot_user and review.state > "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7f448640d1d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [] == [123]
E             
E             Right contains one more item: 123
E             
E             Full diff:
E             + []
E             - [
E             -     123,
E             - ]

tests/test_github_client.py:685: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [] == [123]
  
  Right contains one more item: 123
  
  Full diff:
  + []
  - [
  -     123,
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.13s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 2, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -622,7 +622,7 @@
 
                 bot_reviews: list[BotReview] = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state in (
+                    if review.user.login > bot_user and review.state in (
                         "APPROVED",
                         "DISMISSED",
                     ):
...............................................................F
=================================== FAILURES ===================================
______ TestFindBotApprovalReviews.test_find_bot_approval_reviews_success _______

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7fc1dd7c1450>

    def test_find_bot_approval_reviews_success(self):
        """Test successful bot approval review state lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            bot_approved_review = Mock()
            bot_approved_review.user.login = "stampbot[bot]"
            bot_approved_review.state = "APPROVED"
            bot_approved_review.id = 123
            bot_approved_review.commit_id = "headsha"
    
            bot_dismissed_review = Mock()
            bot_dismissed_review.user.login = "stampbot[bot]"
            bot_dismissed_review.state = "DISMISSED"
            bot_dismissed_review.id = 124
            bot_dismissed_review.commit_id = "oldsha"
    
            bot_commented_review = Mock()
            bot_commented_review.user.login = "stampbot[bot]"
            bot_commented_review.state = "COMMENTED"
            bot_commented_review.id = 125
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [
                bot_approved_review,
                bot_dismissed_review,
                bot_commented_review,
                other_review,
            ]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
    
>           assert result == [
                {"id": 123, "state": "APPROVED", "commit_id": "headsha"},
                {"id": 124, "state": "DISMISSED", "commit_id": "oldsha"},
            ]
E           AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
E             
E             Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
E             
E             Full diff:
E             + []
E             - [
E             -     {
E             -         'commit_id': 'headsha',
E             -         'id': 123,
E             -         'state': 'APPROVED',
E             -     },
E             -     {
E             -         'commit_id': 'oldsha',
E             -         'id': 124,
E             -         'state': 'DISMISSED',
E             -     },
E             - ]

tests/test_github_client.py:790: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_success - AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
  
  Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
  
  Full diff:
  + []
  - [
  -     {
  -         'commit_id': 'headsha',
  -         'id': 123,
  -         'state': 'APPROVED',
  -     },
  -     {
  -         'commit_id': 'oldsha',
  -         'id': 124,
  -         'state': 'DISMISSED',
  -     },
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 63 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 3, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -876,7 +876,7 @@
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
-                if e.status == 404:
+                if e.status > 404:
                     add_span_attributes(span, {"github.label_found": False})
                     set_span_ok(span)
                     return False
........................................................................ [ 30%]
...F
=================================== FAILURES ===================================
________________ TestRepoHasLabel.test_repo_has_label_not_found ________________

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f22e87fdd10>

    def test_repo_has_label_not_found(self):
        """Test repo_has_label returns False when label is missing."""
        from github.GithubException import GithubException
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = GithubException(404, {"message": "Not Found"}, None)
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.repo_has_label(123456, "owner/repo", "missing")
    
>           assert result is False
E           assert None is False

tests/test_github_client.py:1277: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:55:20 [debug    ] Could not verify label missing in owner/repo: 404 {"message": "Not Found"} extra={'repo': 'owner/repo', 'label': 'missing', 'installation_id': 123456, 'error': '404 {"message": "Not Found"}'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_not_found - assert None is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 75 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 0, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if review.user.login >= bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 1, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if review.user.login == bot_user and review.state >= "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.29s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 2, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -622,7 +622,7 @@
 
                 bot_reviews: list[BotReview] = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state in (
+                    if review.user.login >= bot_user and review.state in (
                         "APPROVED",
                         "DISMISSED",
                     ):
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 3, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -876,7 +876,7 @@
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
-                if e.status == 404:
+                if e.status >= 404:
                     add_span_attributes(span, {"github.label_found": False})
                     set_span_ok(span)
                     return False
........................................................................ [ 30%]
....F
=================================== FAILURES ===================================
____________ TestRepoHasLabel.test_repo_has_label_github_exception _____________

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f5199b3cd60>

    def test_repo_has_label_github_exception(self):
        """Test repo_has_label returns None on GitHubException errors."""
        from github.GithubException import GithubException
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = GithubException(500, {"message": "Error"}, None)
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.repo_has_label(123456, "owner/repo", "autoapprove")
    
>           assert result is None
E           assert False is None

tests/test_github_client.py:1315: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_github_exception - assert False is None
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 76 passed, 3 deselected, 1 warning in 2.16s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 0, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if review.user.login is bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7f43b9c691d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [] == [123]
E             
E             Right contains one more item: 123
E             
E             Full diff:
E             + []
E             - [
E             -     123,
E             - ]

tests/test_github_client.py:685: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [] == [123]
  
  Right contains one more item: 123
  
  Full diff:
  + []
  - [
  -     123,
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.13s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 1, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if review.user.login == bot_user and review.state is "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_github_client.py::TestGitHubAppClientInit::test_init_creates_uninitialized_client
  /home/runner/work/stampbot/stampbot/stampbot/github_client.py:546: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    if review.user.login == bot_user and review.state is "APPROVED":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 2 warnings in 3.23s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 2, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -622,7 +622,7 @@
 
                 bot_reviews: list[BotReview] = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state in (
+                    if review.user.login is bot_user and review.state in (
                         "APPROVED",
                         "DISMISSED",
                     ):
...............................................................F
=================================== FAILURES ===================================
______ TestFindBotApprovalReviews.test_find_bot_approval_reviews_success _______

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7f3f74469450>

    def test_find_bot_approval_reviews_success(self):
        """Test successful bot approval review state lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            bot_approved_review = Mock()
            bot_approved_review.user.login = "stampbot[bot]"
            bot_approved_review.state = "APPROVED"
            bot_approved_review.id = 123
            bot_approved_review.commit_id = "headsha"
    
            bot_dismissed_review = Mock()
            bot_dismissed_review.user.login = "stampbot[bot]"
            bot_dismissed_review.state = "DISMISSED"
            bot_dismissed_review.id = 124
            bot_dismissed_review.commit_id = "oldsha"
    
            bot_commented_review = Mock()
            bot_commented_review.user.login = "stampbot[bot]"
            bot_commented_review.state = "COMMENTED"
            bot_commented_review.id = 125
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [
                bot_approved_review,
                bot_dismissed_review,
                bot_commented_review,
                other_review,
            ]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
    
>           assert result == [
                {"id": 123, "state": "APPROVED", "commit_id": "headsha"},
                {"id": 124, "state": "DISMISSED", "commit_id": "oldsha"},
            ]
E           AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
E             
E             Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
E             
E             Full diff:
E             + []
E             - [
E             -     {
E             -         'commit_id': 'headsha',
E             -         'id': 123,
E             -         'state': 'APPROVED',
E             -     },
E             -     {
E             -         'commit_id': 'oldsha',
E             -         'id': 124,
E             -         'state': 'DISMISSED',
E             -     },
E             - ]

tests/test_github_client.py:790: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_success - AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
  
  Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
  
  Full diff:
  + []
  - [
  -     {
  -         'commit_id': 'headsha',
  -         'id': 123,
  -         'state': 'APPROVED',
  -     },
  -     {
  -         'commit_id': 'oldsha',
  -         'id': 124,
  -         'state': 'DISMISSED',
  -     },
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 63 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 0, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if review.user.login is not bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7f96defb11d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [123, 456] == [123]
E             
E             Left contains one more item: 456
E             
E             Full diff:
E               [
E                   123,
E             +     456,
E               ]

tests/test_github_client.py:685: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [123, 456] == [123]
  
  Left contains one more item: 456
  
  Full diff:
    [
        123,
  +     456,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.16s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 1, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if review.user.login == bot_user and review.state is not "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7fa1c8edd1d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [] == [123]
E             
E             Right contains one more item: 123
E             
E             Full diff:
E             + []
E             - [
E             -     123,
E             - ]

tests/test_github_client.py:685: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_github_client.py::TestGitHubAppClientInit::test_init_creates_uninitialized_client
  /home/runner/work/stampbot/stampbot/stampbot/github_client.py:546: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    if review.user.login == bot_user and review.state is not "APPROVED":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [] == [123]
  
  Right contains one more item: 123
  
  Full diff:
  + []
  - [
  -     123,
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 2 warnings in 2.13s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 2, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -622,7 +622,7 @@
 
                 bot_reviews: list[BotReview] = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state in (
+                    if review.user.login is not bot_user and review.state in (
                         "APPROVED",
                         "DISMISSED",
                     ):
...............................................................F
=================================== FAILURES ===================================
______ TestFindBotApprovalReviews.test_find_bot_approval_reviews_success _______

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7f10e3ac9450>

    def test_find_bot_approval_reviews_success(self):
        """Test successful bot approval review state lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            bot_approved_review = Mock()
            bot_approved_review.user.login = "stampbot[bot]"
            bot_approved_review.state = "APPROVED"
            bot_approved_review.id = 123
            bot_approved_review.commit_id = "headsha"
    
            bot_dismissed_review = Mock()
            bot_dismissed_review.user.login = "stampbot[bot]"
            bot_dismissed_review.state = "DISMISSED"
            bot_dismissed_review.id = 124
            bot_dismissed_review.commit_id = "oldsha"
    
            bot_commented_review = Mock()
            bot_commented_review.user.login = "stampbot[bot]"
            bot_commented_review.state = "COMMENTED"
            bot_commented_review.id = 125
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [
                bot_approved_review,
                bot_dismissed_review,
                bot_commented_review,
                other_review,
            ]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
    
>           assert result == [
                {"id": 123, "state": "APPROVED", "commit_id": "headsha"},
                {"id": 124, "state": "DISMISSED", "commit_id": "oldsha"},
            ]
E           AssertionError: assert [{'commit_id'...: 'APPROVED'}] == [{'commit_id'... 'DISMISSED'}]
E             
E             Left contains one more item: {'commit_id': <Mock name='mock.commit_id' id='139710445437008'>, 'id': 456, 'state': 'APPROVED'}
E             
E             Full diff:
E               [
E                   {
E                       'commit_id': 'headsha',
E                       'id': 123,
E                       'state': 'APPROVED',
E                   },
E                   {
E                       'commit_id': 'oldsha',
E                       'id': 124,
E                       'state': 'DISMISSED',
E                   },
E             +     {
E             +         'commit_id': <Mock name='mock.commit_id' id='139710445437008'>,
E             +         'id': 456,
E             +         'state': 'APPROVED',
E             +     },
E               ]

tests/test_github_client.py:790: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_success - AssertionError: assert [{'commit_id'...: 'APPROVED'}] == [{'commit_id'... 'DISMISSED'}]
  
  Left contains one more item: {'commit_id': <Mock name='mock.commit_id' id='139710445437008'>, 'id': 456, 'state': 'APPROVED'}
  
  Full diff:
    [
        {
            'commit_id': 'headsha',
            'id': 123,
            'state': 'APPROVED',
        },
        {
            'commit_id': 'oldsha',
            'id': 124,
            'state': 'DISMISSED',
        },
  +     {
  +         'commit_id': <Mock name='mock.commit_id' id='139710445437008'>,
  +         'id': 456,
  +         'state': 'APPROVED',
  +     },
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 63 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceComparisonOperator_GtE_Eq, occurrence: 0, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -958,7 +958,7 @@
                     permission_index = -1
                     required_index = 99
 
-                has_permission = permission_index >= required_index
+                has_permission = permission_index == required_index
 
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceComparisonOperator_GtE_NotEq, occurrence: 0, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -958,7 +958,7 @@
                     permission_index = -1
                     required_index = 99
 
-                has_permission = permission_index >= required_index
+                has_permission = permission_index != required_index
 
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
.................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_true ______________

self = <tests.test_github_client.TestUserHasPermission object at 0x7fcf1c1c96d0>

    def test_user_has_permission_true(self):
        """Test required permission satisfied returns True."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.return_value = "write"
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.user_has_permission(123456, "owner/repo", "alice", "write")
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:868: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_true - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 65 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceComparisonOperator_GtE_Lt, occurrence: 0, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -958,7 +958,7 @@
                     permission_index = -1
                     required_index = 99
 
-                has_permission = permission_index >= required_index
+                has_permission = permission_index < required_index
 
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
.................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_true ______________

self = <tests.test_github_client.TestUserHasPermission object at 0x7fd24ddfd6d0>

    def test_user_has_permission_true(self):
        """Test required permission satisfied returns True."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.return_value = "write"
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.user_has_permission(123456, "owner/repo", "alice", "write")
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:868: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_true - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 65 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceComparisonOperator_GtE_LtE, occurrence: 0, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -958,7 +958,7 @@
                     permission_index = -1
                     required_index = 99
 
-                has_permission = permission_index >= required_index
+                has_permission = permission_index <= required_index
 
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
..................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_false _____________

self = <tests.test_github_client.TestUserHasPermission object at 0x7f7d90151810>

    def test_user_has_permission_false(self):
        """Test insufficient permission returns False."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.return_value = "read"
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.user_has_permission(123456, "owner/repo", "bob", "write")
    
>           assert result is False
E           assert True is False

tests/test_github_client.py:905: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_false - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 66 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceComparisonOperator_GtE_Gt, occurrence: 0, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -958,7 +958,7 @@
                     permission_index = -1
                     required_index = 99
 
-                has_permission = permission_index >= required_index
+                has_permission = permission_index > required_index
 
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
.................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_true ______________

self = <tests.test_github_client.TestUserHasPermission object at 0x7fbcf68416d0>

    def test_user_has_permission_true(self):
        """Test required permission satisfied returns True."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.return_value = "write"
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.user_has_permission(123456, "owner/repo", "alice", "write")
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:868: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_true - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 65 passed, 3 deselected, 1 warning in 2.18s
operator: core/ReplaceComparisonOperator_GtE_Is, occurrence: 0, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -958,7 +958,7 @@
                     permission_index = -1
                     required_index = 99
 
-                has_permission = permission_index >= required_index
+                has_permission = permission_index is required_index
 
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.28s
operator: core/ReplaceComparisonOperator_GtE_IsNot, occurrence: 0, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -958,7 +958,7 @@
                     permission_index = -1
                     required_index = 99
 
-                has_permission = permission_index >= required_index
+                has_permission = permission_index is not required_index
 
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
.................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_true ______________

self = <tests.test_github_client.TestUserHasPermission object at 0x7f6759a0d6d0>

    def test_user_has_permission_true(self):
        """Test required permission satisfied returns True."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.return_value = "write"
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.user_has_permission(123456, "owner/repo", "alice", "write")
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:868: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_true - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 65 passed, 3 deselected, 1 warning in 2.16s
operator: core/ReplaceComparisonOperator_Is_IsNot, occurrence: 0, definition_name: _ensure_initialized
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -76,7 +76,7 @@
 
         # is_configured() guarantees app_id is set, but check for type safety
         app_id = settings.app_id
-        if app_id is None:
+        if app_id is not None:
             raise RuntimeError("App ID not configured")
 
         private_key = self._load_private_key()
.......................................F
=================================== FAILURES ===================================
____ TestEnsureInitialized.test_ensure_initialized_raises_when_app_id_none _____

self = <tests.test_github_client.TestEnsureInitialized object at 0x7fba526703e0>

    def test_ensure_initialized_raises_when_app_id_none(self):
        """Test that _ensure_initialized raises when app_id is None."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
        ):
            mock_settings.app_id = None
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            with pytest.raises(RuntimeError, match="App ID not configured"):
>               client._ensure_initialized()

tests/test_github_client.py:62: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/github_client.py:83: in _ensure_initialized
    self._auth = Auth.AppAuth(app_id, private_key)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <github.Auth.AppAuth object at 0x7fba4f583cb0>, app_id = None
private_key = <MagicMock name='settings.private_key' id='140438171824352'>

    def __init__(
        self,
        app_id: int | str,
        private_key: str | PrivateKeyGenerator | None = None,
        *,
        sign_func: DictSignFunction | None = None,
        jwt_expiry: int = Consts.DEFAULT_JWT_EXPIRY,
        jwt_issued_at: int = Consts.DEFAULT_JWT_ISSUED_AT,
    ):
>       assert isinstance(app_id, (int, str)), app_id
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       AssertionError: None

../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/github/Auth.py:227: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestEnsureInitialized::test_ensure_initialized_raises_when_app_id_none - AssertionError: None
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 39 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceComparisonOperator_Is_IsNot, occurrence: 1, definition_name: _load_private_key
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -111,7 +111,7 @@
         """
         key: str | None = settings.private_key
 
-        if key is None:
+        if key is not None:
             raise RuntimeError("Private key not configured")
 
         # If it looks like PEM content, use directly
........................................F
=================================== FAILURES ===================================
____________ TestEnsureInitialized.test_ensure_initialized_success _____________

self = <tests.test_github_client.TestEnsureInitialized object at 0x7f1ccf450510>

    def test_ensure_initialized_success(self):
        """Test successful initialization."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth") as mock_auth,
            patch("stampbot.github_client.GithubIntegration") as mock_integration,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           client._ensure_initialized()

tests/test_github_client.py:78: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/github_client.py:82: in _ensure_initialized
    private_key = self._load_private_key()
                  ^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f1ccc4ab890>

    def _load_private_key(self) -> str:
        """Load private key from settings or file.
    
        Returns:
            Private key contents as PEM string.
    
        Raises:
            RuntimeError: If private key is not configured.
            ValueError: If private key is not valid PEM format.
            OSError: If private key file cannot be read.
        """
        key: str | None = settings.private_key
    
        if key is not None:
>           raise RuntimeError("Private key not configured")
E           RuntimeError: Private key not configured

stampbot/github_client.py:115: RuntimeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestEnsureInitialized::test_ensure_initialized_success - RuntimeError: Private key not configured
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 40 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceComparisonOperator_IsNot_Is, occurrence: 0, definition_name: integration
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -95,7 +95,7 @@
             RuntimeError: If GitHub App credentials are not configured.
         """
         self._ensure_initialized()
-        assert self._integration is not None  # guaranteed by _ensure_initialized
+        assert self._integration is None  # guaranteed by _ensure_initialized
         return self._integration
 
     def _load_private_key(self) -> str:
................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_success ________

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f414f0102d0>

    def test_get_installation_client_success(self):
        """Test successful installation client creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client._get_installation_client(123456)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:211: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/github_client.py:164: in _get_installation_client
    auth = self.integration.get_access_token(installation_id)
           ^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f414adc98d0>

    @property
    def integration(self) -> GithubIntegration:
        """Get GitHub integration, initializing if needed.
    
        Returns:
            Configured GithubIntegration instance.
    
        Raises:
            RuntimeError: If GitHub App credentials are not configured.
        """
        self._ensure_initialized()
>       assert self._integration is None  # guaranteed by _ensure_initialized
               ^^^^^^^^^^^^^^^^^^^^^^^^^
E       AssertionError

stampbot/github_client.py:98: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_success - AssertionError
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 48 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceUnaryOperator_USub_UAdd, occurrence: 0, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -955,7 +955,7 @@
                     permission_index = permission_order.index(permission)
                     required_index = permission_order.index(required_permission)
                 except ValueError:
-                    permission_index = -1
+                    permission_index = +1
                     required_index = 99
 
                 has_permission = permission_index >= required_index
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceUnaryOperator_USub_UAdd, occurrence: 1, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1039,7 +1039,7 @@
 
                 for team_ref in allowed_teams:
                     # Extract team slug (handle both "org/team" and "team" formats)
-                    team_slug = team_ref.split("/")[-1] if "/" in team_ref else team_ref
+                    team_slug = team_ref.split("/")[+1] if "/" in team_ref else team_ref
 
                     try:
                         team = org.get_team_by_slug(team_slug)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceUnaryOperator_USub_Invert, occurrence: 0, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -955,7 +955,7 @@
                     permission_index = permission_order.index(permission)
                     required_index = permission_order.index(required_permission)
                 except ValueError:
-                    permission_index = -1
+                    permission_index = ~1
                     required_index = 99
 
                 has_permission = permission_index >= required_index
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceUnaryOperator_USub_Invert, occurrence: 1, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1039,7 +1039,7 @@
 
                 for team_ref in allowed_teams:
                     # Extract team slug (handle both "org/team" and "team" formats)
-                    team_slug = team_ref.split("/")[-1] if "/" in team_ref else team_ref
+                    team_slug = team_ref.split("/")[~1] if "/" in team_ref else team_ref
 
                     try:
                         team = org.get_team_by_slug(team_slug)
......................................................................F
=================================== FAILURES ===================================
________ TestGetUserTeamSlugs.test_get_user_team_slugs_with_org_prefix _________

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7f01602dda90>

    def test_get_user_team_slugs_with_org_prefix(self):
        """Test team membership check with org/team format."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_user = Mock()
            mock_team = Mock()
            mock_team.has_in_members.return_value = True
            mock_org = Mock()
            mock_org.get_team_by_slug.return_value = mock_team
    
            mock_github = Mock()
            mock_github.get_organization.return_value = mock_org
            mock_github.get_user.return_value = mock_user
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_user_team_slugs(123456, "acme", "alice", ["acme/release-team"])
    
            # Should extract "release-team" from "acme/release-team"
>           mock_org.get_team_by_slug.assert_called_with("release-team")

tests/test_github_client.py:1077: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_organization().get_team_by_slug' id='139643812574752'>
args = ('release-team',), kwargs = {}, expected = call('release-team')
actual = call('acme')
_error_message = <function NonCallableMock.assert_called_with.<locals>._error_message at 0x7f015bd94880>
cause = None

    def assert_called_with(self, /, *args, **kwargs):
        """assert that the last call was made with the specified arguments.
    
        Raises an AssertionError if the args and keyword args passed in are
        different to the last call to the mock."""
        if self.call_args is None:
            expected = self._format_mock_call_signature(args, kwargs)
            actual = 'not called.'
            error_message = ('expected call not found.\nExpected: %s\n  Actual: %s'
                    % (expected, actual))
            raise AssertionError(error_message)
    
        def _error_message():
            msg = self._format_mock_failure_message(args, kwargs)
            return msg
        expected = self._call_matcher(_Call((args, kwargs), two=True))
        actual = self._call_matcher(self.call_args)
        if actual != expected:
            cause = expected if isinstance(expected, Exception) else None
>           raise AssertionError(_error_message()) from cause
E           AssertionError: expected call not found.
E           Expected: get_team_by_slug('release-team')
E             Actual: get_team_by_slug('acme')

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:986: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:55:34 [debug    ] User alice is a member of team acme extra={'org': 'acme', 'username': 'alice', 'team': 'acme'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_with_org_prefix - AssertionError: expected call not found.
Expected: get_team_by_slug('release-team')
  Actual: get_team_by_slug('acme')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 70 passed, 3 deselected, 1 warning in 2.21s
operator: core/ReplaceUnaryOperator_USub_Not, occurrence: 0, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -955,7 +955,7 @@
                     permission_index = permission_order.index(permission)
                     required_index = permission_order.index(required_permission)
                 except ValueError:
-                    permission_index = -1
+                    permission_index = not 1
                     required_index = 99
 
                 has_permission = permission_index >= required_index
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceUnaryOperator_USub_Not, occurrence: 1, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1039,7 +1039,7 @@
 
                 for team_ref in allowed_teams:
                     # Extract team slug (handle both "org/team" and "team" formats)
-                    team_slug = team_ref.split("/")[-1] if "/" in team_ref else team_ref
+                    team_slug = team_ref.split("/")[not 1] if "/" in team_ref else team_ref
 
                     try:
                         team = org.get_team_by_slug(team_slug)
......................................................................F
=================================== FAILURES ===================================
________ TestGetUserTeamSlugs.test_get_user_team_slugs_with_org_prefix _________

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7fa3d29dda90>

    def test_get_user_team_slugs_with_org_prefix(self):
        """Test team membership check with org/team format."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_user = Mock()
            mock_team = Mock()
            mock_team.has_in_members.return_value = True
            mock_org = Mock()
            mock_org.get_team_by_slug.return_value = mock_team
    
            mock_github = Mock()
            mock_github.get_organization.return_value = mock_org
            mock_github.get_user.return_value = mock_user
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_user_team_slugs(123456, "acme", "alice", ["acme/release-team"])
    
            # Should extract "release-team" from "acme/release-team"
>           mock_org.get_team_by_slug.assert_called_with("release-team")

tests/test_github_client.py:1077: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_organization().get_team_by_slug' id='140341517219360'>
args = ('release-team',), kwargs = {}, expected = call('release-team')
actual = call('acme')
_error_message = <function NonCallableMock.assert_called_with.<locals>._error_message at 0x7fa3ce494880>
cause = None

    def assert_called_with(self, /, *args, **kwargs):
        """assert that the last call was made with the specified arguments.
    
        Raises an AssertionError if the args and keyword args passed in are
        different to the last call to the mock."""
        if self.call_args is None:
            expected = self._format_mock_call_signature(args, kwargs)
            actual = 'not called.'
            error_message = ('expected call not found.\nExpected: %s\n  Actual: %s'
                    % (expected, actual))
            raise AssertionError(error_message)
    
        def _error_message():
            msg = self._format_mock_failure_message(args, kwargs)
            return msg
        expected = self._call_matcher(_Call((args, kwargs), two=True))
        actual = self._call_matcher(self.call_args)
        if actual != expected:
            cause = expected if isinstance(expected, Exception) else None
>           raise AssertionError(_error_message()) from cause
E           AssertionError: expected call not found.
E           Expected: get_team_by_slug('release-team')
E             Actual: get_team_by_slug('acme')

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:986: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:47:36 [debug    ] User alice is a member of team acme extra={'org': 'acme', 'username': 'alice', 'team': 'acme'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_with_org_prefix - AssertionError: expected call not found.
Expected: get_team_by_slug('release-team')
  Actual: get_team_by_slug('acme')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 70 passed, 3 deselected, 1 warning in 2.18s
operator: core/ReplaceUnaryOperator_Delete_USub, occurrence: 0, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -955,7 +955,7 @@
                     permission_index = permission_order.index(permission)
                     required_index = permission_order.index(required_permission)
                 except ValueError:
-                    permission_index = -1
+                    permission_index = 1
                     required_index = 99
 
                 has_permission = permission_index >= required_index
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceUnaryOperator_Delete_USub, occurrence: 1, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1039,7 +1039,7 @@
 
                 for team_ref in allowed_teams:
                     # Extract team slug (handle both "org/team" and "team" formats)
-                    team_slug = team_ref.split("/")[-1] if "/" in team_ref else team_ref
+                    team_slug = team_ref.split("/")[1] if "/" in team_ref else team_ref
 
                     try:
                         team = org.get_team_by_slug(team_slug)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 0, definition_name: _ensure_initialized
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -71,7 +71,7 @@
         if self._initialized:
             return
 
-        if not is_configured():
+        if  is_configured():
             raise RuntimeError("GitHub App not configured. Visit /setup to create your GitHub App.")
 
         # is_configured() guarantees app_id is set, but check for type safety
......................................F
=================================== FAILURES ===================================
___ TestEnsureInitialized.test_ensure_initialized_raises_when_not_configured ___

self = <tests.test_github_client.TestEnsureInitialized object at 0x7fdbdc20fed0>

    def test_ensure_initialized_raises_when_not_configured(self):
        """Test that _ensure_initialized raises when app not configured."""
        with patch("stampbot.github_client.is_configured", return_value=False):
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           with pytest.raises(RuntimeError, match="GitHub App not configured"):
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           Failed: DID NOT RAISE <class 'RuntimeError'>

tests/test_github_client.py:47: Failed
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestEnsureInitialized::test_ensure_initialized_raises_when_not_configured - Failed: DID NOT RAISE <class 'RuntimeError'>
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 38 passed, 3 deselected, 1 warning in 2.09s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 1, definition_name: _load_private_key
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -126,7 +126,7 @@
 
             # Security: prevent path traversal by ensuring the path doesn't escape
             # expected directories and doesn't follow symlinks to unexpected locations
-            if ".." in str(key_path) or not os.path.isfile(key_path):
+            if ".." in str(key_path) or  os.path.isfile(key_path):
                 raise ValueError(f"Invalid private key path: {key}")
 
             try:
............................................F
=================================== FAILURES ===================================
___________ TestLoadPrivateKey.test_load_private_key_reads_from_file ___________

self = <tests.test_github_client.TestLoadPrivateKey object at 0x7f4386054050>
tmp_path = PosixPath('/tmp/pytest-of-runner/pytest-973/test_load_private_key_reads_fr0')

    def test_load_private_key_reads_from_file(self, tmp_path):
        """Test that private key is read from file when path provided."""
        pem_key = TEST_PEM_KEY
        key_file = tmp_path / "private-key.pem"
        key_file.write_text(pem_key)
    
        with patch("stampbot.github_client.settings") as mock_settings:
            mock_settings.private_key = str(key_file)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client._load_private_key()
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:136: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f43869a1050>

    def _load_private_key(self) -> str:
        """Load private key from settings or file.
    
        Returns:
            Private key contents as PEM string.
    
        Raises:
            RuntimeError: If private key is not configured.
            ValueError: If private key is not valid PEM format.
            OSError: If private key file cannot be read.
        """
        key: str | None = settings.private_key
    
        if key is None:
            raise RuntimeError("Private key not configured")
    
        # If it looks like PEM content, use directly
        if key.startswith("-----BEGIN"):
            pem_content = key
        else:
            # Treat as file path - read the file
            import os
            from pathlib import Path
    
            key_path = Path(key).resolve()
    
            # Security: prevent path traversal by ensuring the path doesn't escape
            # expected directories and doesn't follow symlinks to unexpected locations
            if ".." in str(key_path) or  os.path.isfile(key_path):
>               raise ValueError(f"Invalid private key path: {key}")
E               ValueError: Invalid private key path: /tmp/pytest-of-runner/pytest-973/test_load_private_key_reads_fr0/private-key.pem

stampbot/github_client.py:130: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestLoadPrivateKey::test_load_private_key_reads_from_file - ValueError: Invalid private key path: /tmp/pytest-of-runner/pytest-973/test_load_private_key_reads_fr0/private-key.pem
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 44 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 2, definition_name: _load_private_key
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -137,7 +137,7 @@
                 raise
 
         # Validate the content is actually a PEM-formatted key
-        if not pem_content.strip().startswith("-----BEGIN"):
+        if  pem_content.strip().startswith("-----BEGIN"):
             raise ValueError("Private key must be in PEM format")
 
         return pem_content
........................................F
=================================== FAILURES ===================================
____________ TestEnsureInitialized.test_ensure_initialized_success _____________

self = <tests.test_github_client.TestEnsureInitialized object at 0x7f71c1754510>

    def test_ensure_initialized_success(self):
        """Test successful initialization."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth") as mock_auth,
            patch("stampbot.github_client.GithubIntegration") as mock_integration,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           client._ensure_initialized()

tests/test_github_client.py:78: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/github_client.py:82: in _ensure_initialized
    private_key = self._load_private_key()
                  ^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f71be793890>

    def _load_private_key(self) -> str:
        """Load private key from settings or file.
    
        Returns:
            Private key contents as PEM string.
    
        Raises:
            RuntimeError: If private key is not configured.
            ValueError: If private key is not valid PEM format.
            OSError: If private key file cannot be read.
        """
        key: str | None = settings.private_key
    
        if key is None:
            raise RuntimeError("Private key not configured")
    
        # If it looks like PEM content, use directly
        if key.startswith("-----BEGIN"):
            pem_content = key
        else:
            # Treat as file path - read the file
            import os
            from pathlib import Path
    
            key_path = Path(key).resolve()
    
            # Security: prevent path traversal by ensuring the path doesn't escape
            # expected directories and doesn't follow symlinks to unexpected locations
            if ".." in str(key_path) or not os.path.isfile(key_path):
                raise ValueError(f"Invalid private key path: {key}")
    
            try:
                with open(key_path) as f:
                    pem_content = f.read()
            except Exception as e:
                logger.error("Failed to read private key from file: %s", e)
                raise
    
        # Validate the content is actually a PEM-formatted key
        if  pem_content.strip().startswith("-----BEGIN"):
>           raise ValueError("Private key must be in PEM format")
E           ValueError: Private key must be in PEM format

stampbot/github_client.py:141: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestEnsureInitialized::test_ensure_initialized_success - ValueError: Private key must be in PEM format
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 40 passed, 3 deselected, 1 warning in 2.14s
operator: core/AddNot, occurrence: 0, definition_name: _ensure_initialized
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -68,7 +68,7 @@
         Raises:
             RuntimeError: If GitHub App credentials are not configured.
         """
-        if self._initialized:
+        if not self._initialized:
             return
 
         if not is_configured():
......................................F
=================================== FAILURES ===================================
___ TestEnsureInitialized.test_ensure_initialized_raises_when_not_configured ___

self = <tests.test_github_client.TestEnsureInitialized object at 0x7fe52ff07ed0>

    def test_ensure_initialized_raises_when_not_configured(self):
        """Test that _ensure_initialized raises when app not configured."""
        with patch("stampbot.github_client.is_configured", return_value=False):
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           with pytest.raises(RuntimeError, match="GitHub App not configured"):
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           Failed: DID NOT RAISE <class 'RuntimeError'>

tests/test_github_client.py:47: Failed
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestEnsureInitialized::test_ensure_initialized_raises_when_not_configured - Failed: DID NOT RAISE <class 'RuntimeError'>
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 38 passed, 3 deselected, 1 warning in 2.08s
operator: core/AddNot, occurrence: 1, definition_name: _ensure_initialized
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -71,7 +71,7 @@
         if self._initialized:
             return
 
-        if not is_configured():
+        if not not is_configured():
             raise RuntimeError("GitHub App not configured. Visit /setup to create your GitHub App.")
 
         # is_configured() guarantees app_id is set, but check for type safety
......................................F
=================================== FAILURES ===================================
___ TestEnsureInitialized.test_ensure_initialized_raises_when_not_configured ___

self = <tests.test_github_client.TestEnsureInitialized object at 0x7f19b80bfed0>

    def test_ensure_initialized_raises_when_not_configured(self):
        """Test that _ensure_initialized raises when app not configured."""
        with patch("stampbot.github_client.is_configured", return_value=False):
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           with pytest.raises(RuntimeError, match="GitHub App not configured"):
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           Failed: DID NOT RAISE <class 'RuntimeError'>

tests/test_github_client.py:47: Failed
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestEnsureInitialized::test_ensure_initialized_raises_when_not_configured - Failed: DID NOT RAISE <class 'RuntimeError'>
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 38 passed, 3 deselected, 1 warning in 2.11s
operator: core/AddNot, occurrence: 2, definition_name: _ensure_initialized
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -76,7 +76,7 @@
 
         # is_configured() guarantees app_id is set, but check for type safety
         app_id = settings.app_id
-        if app_id is None:
+        if not app_id is None:
             raise RuntimeError("App ID not configured")
 
         private_key = self._load_private_key()
.......................................F
=================================== FAILURES ===================================
____ TestEnsureInitialized.test_ensure_initialized_raises_when_app_id_none _____

self = <tests.test_github_client.TestEnsureInitialized object at 0x7fa2972543e0>

    def test_ensure_initialized_raises_when_app_id_none(self):
        """Test that _ensure_initialized raises when app_id is None."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
        ):
            mock_settings.app_id = None
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            with pytest.raises(RuntimeError, match="App ID not configured"):
>               client._ensure_initialized()

tests/test_github_client.py:62: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/github_client.py:83: in _ensure_initialized
    self._auth = Auth.AppAuth(app_id, private_key)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <github.Auth.AppAuth object at 0x7fa29417fcb0>, app_id = None
private_key = <MagicMock name='settings.private_key' id='140336246026464'>

    def __init__(
        self,
        app_id: int | str,
        private_key: str | PrivateKeyGenerator | None = None,
        *,
        sign_func: DictSignFunction | None = None,
        jwt_expiry: int = Consts.DEFAULT_JWT_EXPIRY,
        jwt_issued_at: int = Consts.DEFAULT_JWT_ISSUED_AT,
    ):
>       assert isinstance(app_id, (int, str)), app_id
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       AssertionError: None

../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/github/Auth.py:227: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestEnsureInitialized::test_ensure_initialized_raises_when_app_id_none - AssertionError: None
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 39 passed, 3 deselected, 1 warning in 2.16s
operator: core/AddNot, occurrence: 3, definition_name: integration
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -95,7 +95,7 @@
             RuntimeError: If GitHub App credentials are not configured.
         """
         self._ensure_initialized()
-        assert self._integration is not None  # guaranteed by _ensure_initialized
+        assert not self._integration is not None  # guaranteed by _ensure_initialized
         return self._integration
 
     def _load_private_key(self) -> str:
................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_success ________

self = <tests.test_github_client.TestGetInstallationClient object at 0x7ff5da7c42d0>

    def test_get_installation_client_success(self):
        """Test successful installation client creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client._get_installation_client(123456)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:211: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/github_client.py:164: in _get_installation_client
    auth = self.integration.get_access_token(installation_id)
           ^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7ff5d65cd8d0>

    @property
    def integration(self) -> GithubIntegration:
        """Get GitHub integration, initializing if needed.
    
        Returns:
            Configured GithubIntegration instance.
    
        Raises:
            RuntimeError: If GitHub App credentials are not configured.
        """
        self._ensure_initialized()
>       assert not self._integration is not None  # guaranteed by _ensure_initialized
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       AssertionError

stampbot/github_client.py:98: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_success - AssertionError
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 48 passed, 3 deselected, 1 warning in 2.15s
operator: core/AddNot, occurrence: 4, definition_name: _load_private_key
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -111,7 +111,7 @@
         """
         key: str | None = settings.private_key
 
-        if key is None:
+        if not key is None:
             raise RuntimeError("Private key not configured")
 
         # If it looks like PEM content, use directly
........................................F
=================================== FAILURES ===================================
____________ TestEnsureInitialized.test_ensure_initialized_success _____________

self = <tests.test_github_client.TestEnsureInitialized object at 0x7f64a6d68510>

    def test_ensure_initialized_success(self):
        """Test successful initialization."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth") as mock_auth,
            patch("stampbot.github_client.GithubIntegration") as mock_integration,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           client._ensure_initialized()

tests/test_github_client.py:78: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/github_client.py:82: in _ensure_initialized
    private_key = self._load_private_key()
                  ^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f64a3c0b890>

    def _load_private_key(self) -> str:
        """Load private key from settings or file.
    
        Returns:
            Private key contents as PEM string.
    
        Raises:
            RuntimeError: If private key is not configured.
            ValueError: If private key is not valid PEM format.
            OSError: If private key file cannot be read.
        """
        key: str | None = settings.private_key
    
        if not key is None:
>           raise RuntimeError("Private key not configured")
E           RuntimeError: Private key not configured

stampbot/github_client.py:115: RuntimeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestEnsureInitialized::test_ensure_initialized_success - RuntimeError: Private key not configured
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 40 passed, 3 deselected, 1 warning in 2.16s
operator: core/AddNot, occurrence: 5, definition_name: _load_private_key
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -115,7 +115,7 @@
             raise RuntimeError("Private key not configured")
 
         # If it looks like PEM content, use directly
-        if key.startswith("-----BEGIN"):
+        if not key.startswith("-----BEGIN"):
             pem_content = key
         else:
             # Treat as file path - read the file
........................................F
=================================== FAILURES ===================================
____________ TestEnsureInitialized.test_ensure_initialized_success _____________

self = <tests.test_github_client.TestEnsureInitialized object at 0x7f6d68f70510>

    def test_ensure_initialized_success(self):
        """Test successful initialization."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth") as mock_auth,
            patch("stampbot.github_client.GithubIntegration") as mock_integration,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           client._ensure_initialized()

tests/test_github_client.py:78: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/github_client.py:82: in _ensure_initialized
    private_key = self._load_private_key()
                  ^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f6d65e0b890>

    def _load_private_key(self) -> str:
        """Load private key from settings or file.
    
        Returns:
            Private key contents as PEM string.
    
        Raises:
            RuntimeError: If private key is not configured.
            ValueError: If private key is not valid PEM format.
            OSError: If private key file cannot be read.
        """
        key: str | None = settings.private_key
    
        if key is None:
            raise RuntimeError("Private key not configured")
    
        # If it looks like PEM content, use directly
        if not key.startswith("-----BEGIN"):
            pem_content = key
        else:
            # Treat as file path - read the file
            import os
            from pathlib import Path
    
            key_path = Path(key).resolve()
    
            # Security: prevent path traversal by ensuring the path doesn't escape
            # expected directories and doesn't follow symlinks to unexpected locations
            if ".." in str(key_path) or not os.path.isfile(key_path):
>               raise ValueError(f"Invalid private key path: {key}")
E               ValueError: Invalid private key path: -----BEGIN RSA PRIVATE KEY-----
E               test
E               -----END RSA PRIVATE KEY-----

stampbot/github_client.py:130: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestEnsureInitialized::test_ensure_initialized_success - ValueError: Invalid private key path: -----BEGIN RSA PRIVATE KEY-----
test
-----END RSA PRIVATE KEY-----
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 40 passed, 3 deselected, 1 warning in 2.14s
operator: core/AddNot, occurrence: 6, definition_name: _load_private_key
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -126,7 +126,7 @@
 
             # Security: prevent path traversal by ensuring the path doesn't escape
             # expected directories and doesn't follow symlinks to unexpected locations
-            if ".." in str(key_path) or not os.path.isfile(key_path):
+            if not ".." in str(key_path) or not os.path.isfile(key_path):
                 raise ValueError(f"Invalid private key path: {key}")
 
             try:
............................................F
=================================== FAILURES ===================================
___________ TestLoadPrivateKey.test_load_private_key_reads_from_file ___________

self = <tests.test_github_client.TestLoadPrivateKey object at 0x7f598264c050>
tmp_path = PosixPath('/tmp/pytest-of-runner/pytest-361/test_load_private_key_reads_fr0')

    def test_load_private_key_reads_from_file(self, tmp_path):
        """Test that private key is read from file when path provided."""
        pem_key = TEST_PEM_KEY
        key_file = tmp_path / "private-key.pem"
        key_file.write_text(pem_key)
    
        with patch("stampbot.github_client.settings") as mock_settings:
            mock_settings.private_key = str(key_file)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client._load_private_key()
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:136: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f5982fa1050>

    def _load_private_key(self) -> str:
        """Load private key from settings or file.
    
        Returns:
            Private key contents as PEM string.
    
        Raises:
            RuntimeError: If private key is not configured.
            ValueError: If private key is not valid PEM format.
            OSError: If private key file cannot be read.
        """
        key: str | None = settings.private_key
    
        if key is None:
            raise RuntimeError("Private key not configured")
    
        # If it looks like PEM content, use directly
        if key.startswith("-----BEGIN"):
            pem_content = key
        else:
            # Treat as file path - read the file
            import os
            from pathlib import Path
    
            key_path = Path(key).resolve()
    
            # Security: prevent path traversal by ensuring the path doesn't escape
            # expected directories and doesn't follow symlinks to unexpected locations
            if not ".." in str(key_path) or not os.path.isfile(key_path):
>               raise ValueError(f"Invalid private key path: {key}")
E               ValueError: Invalid private key path: /tmp/pytest-of-runner/pytest-361/test_load_private_key_reads_fr0/private-key.pem

stampbot/github_client.py:130: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestLoadPrivateKey::test_load_private_key_reads_from_file - ValueError: Invalid private key path: /tmp/pytest-of-runner/pytest-361/test_load_private_key_reads_fr0/private-key.pem
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 44 passed, 3 deselected, 1 warning in 2.13s
operator: core/AddNot, occurrence: 7, definition_name: _load_private_key
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -137,7 +137,7 @@
                 raise
 
         # Validate the content is actually a PEM-formatted key
-        if not pem_content.strip().startswith("-----BEGIN"):
+        if not not pem_content.strip().startswith("-----BEGIN"):
             raise ValueError("Private key must be in PEM format")
 
         return pem_content
........................................F
=================================== FAILURES ===================================
____________ TestEnsureInitialized.test_ensure_initialized_success _____________

self = <tests.test_github_client.TestEnsureInitialized object at 0x7f5aee334510>

    def test_ensure_initialized_success(self):
        """Test successful initialization."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth") as mock_auth,
            patch("stampbot.github_client.GithubIntegration") as mock_integration,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           client._ensure_initialized()

tests/test_github_client.py:78: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/github_client.py:82: in _ensure_initialized
    private_key = self._load_private_key()
                  ^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f5aeb397890>

    def _load_private_key(self) -> str:
        """Load private key from settings or file.
    
        Returns:
            Private key contents as PEM string.
    
        Raises:
            RuntimeError: If private key is not configured.
            ValueError: If private key is not valid PEM format.
            OSError: If private key file cannot be read.
        """
        key: str | None = settings.private_key
    
        if key is None:
            raise RuntimeError("Private key not configured")
    
        # If it looks like PEM content, use directly
        if key.startswith("-----BEGIN"):
            pem_content = key
        else:
            # Treat as file path - read the file
            import os
            from pathlib import Path
    
            key_path = Path(key).resolve()
    
            # Security: prevent path traversal by ensuring the path doesn't escape
            # expected directories and doesn't follow symlinks to unexpected locations
            if ".." in str(key_path) or not os.path.isfile(key_path):
                raise ValueError(f"Invalid private key path: {key}")
    
            try:
                with open(key_path) as f:
                    pem_content = f.read()
            except Exception as e:
                logger.error("Failed to read private key from file: %s", e)
                raise
    
        # Validate the content is actually a PEM-formatted key
        if not not pem_content.strip().startswith("-----BEGIN"):
>           raise ValueError("Private key must be in PEM format")
E           ValueError: Private key must be in PEM format

stampbot/github_client.py:141: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestEnsureInitialized::test_ensure_initialized_success - ValueError: Private key must be in PEM format
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 40 passed, 3 deselected, 1 warning in 2.14s
operator: core/AddNot, occurrence: 8, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -465,7 +465,7 @@
                 repo = client.get_repo(repo_full_name)
 
                 content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
-                if isinstance(content, list):
+                if not isinstance(content, list):
                     duration = time.time() - start_time
                     github_api_request_duration_seconds.labels(operation="get_file").observe(
                         duration
..........................................................F
=================================== FAILURES ===================================
__________________ TestGetRepoFile.test_get_repo_file_success __________________

self = <tests.test_github_client.TestGetRepoFile object at 0x7feaa38a8f50>

    def test_get_repo_file_success(self):
        """Test successful file retrieval."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_content = Mock()
            mock_content.decoded_content = b"file content"
            mock_repo = Mock()
            mock_repo.get_contents.return_value = mock_content
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_repo_file(123456, "owner/repo", "stampbot.toml")
    
>           assert result == "file content"
E           AssertionError: assert None == 'file content'

tests/test_github_client.py:557: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetRepoFile::test_get_repo_file_success - AssertionError: assert None == 'file content'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 58 passed, 3 deselected, 1 warning in 2.14s
operator: core/AddNot, occurrence: 9, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if not review.user.login == bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7f9672bd11d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [456] == [123]
E             
E             At index 0 diff: 456 != 123
E             
E             Full diff:
E               [
E             -     123,
E             +     456,
E               ]

tests/test_github_client.py:685: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [456] == [123]
  
  At index 0 diff: 456 != 123
  
  Full diff:
    [
  -     123,
  +     456,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.13s
operator: core/AddNot, occurrence: 10, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -622,7 +622,7 @@
 
                 bot_reviews: list[BotReview] = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state in (
+                    if not review.user.login == bot_user and review.state in (
                         "APPROVED",
                         "DISMISSED",
                     ):
...............................................................F
=================================== FAILURES ===================================
______ TestFindBotApprovalReviews.test_find_bot_approval_reviews_success _______

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7f5d3b311450>

    def test_find_bot_approval_reviews_success(self):
        """Test successful bot approval review state lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            bot_approved_review = Mock()
            bot_approved_review.user.login = "stampbot[bot]"
            bot_approved_review.state = "APPROVED"
            bot_approved_review.id = 123
            bot_approved_review.commit_id = "headsha"
    
            bot_dismissed_review = Mock()
            bot_dismissed_review.user.login = "stampbot[bot]"
            bot_dismissed_review.state = "DISMISSED"
            bot_dismissed_review.id = 124
            bot_dismissed_review.commit_id = "oldsha"
    
            bot_commented_review = Mock()
            bot_commented_review.user.login = "stampbot[bot]"
            bot_commented_review.state = "COMMENTED"
            bot_commented_review.id = 125
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [
                bot_approved_review,
                bot_dismissed_review,
                bot_commented_review,
                other_review,
            ]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
    
>           assert result == [
                {"id": 123, "state": "APPROVED", "commit_id": "headsha"},
                {"id": 124, "state": "DISMISSED", "commit_id": "oldsha"},
            ]
E           AssertionError: assert [{'commit_id'...: 'APPROVED'}] == [{'commit_id'... 'DISMISSED'}]
E             
E             At index 0 diff: {'id': 456, 'state': 'APPROVED', 'commit_id': <Mock name='mock.commit_id' id='140038330728528'>} != {'id': 123, 'state': 'APPROVED', 'commit_id': 'headsha'}
E             Right contains one more item: {'commit_id': 'oldsha', 'id': 124, 'state': 'DISMISSED'}
E             
E             Full diff:
E               [
E                   {
E             -         'commit_id': 'headsha',
E             +         'commit_id': <Mock name='mock.commit_id' id='140038330728528'>,
E             -         'id': 123,
E             ?               ^^^
E             +         'id': 456,
E             ?               ^^^
E                       'state': 'APPROVED',
E                   },
E             -     {
E             -         'commit_id': 'oldsha',
E             -         'id': 124,
E             -         'state': 'DISMISSED',
E             -     },
E               ]

tests/test_github_client.py:790: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_success - AssertionError: assert [{'commit_id'...: 'APPROVED'}] == [{'commit_id'... 'DISMISSED'}]
  
  At index 0 diff: {'id': 456, 'state': 'APPROVED', 'commit_id': <Mock name='mock.commit_id' id='140038330728528'>} != {'id': 123, 'state': 'APPROVED', 'commit_id': 'headsha'}
  Right contains one more item: {'commit_id': 'oldsha', 'id': 124, 'state': 'DISMISSED'}
  
  Full diff:
    [
        {
  -         'commit_id': 'headsha',
  +         'commit_id': <Mock name='mock.commit_id' id='140038330728528'>,
  -         'id': 123,
  ?               ^^^
  +         'id': 456,
  ?               ^^^
            'state': 'APPROVED',
        },
  -     {
  -         'commit_id': 'oldsha',
  -         'id': 124,
  -         'state': 'DISMISSED',
  -     },
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 63 passed, 3 deselected, 1 warning in 2.17s
operator: core/AddNot, occurrence: 11, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -876,7 +876,7 @@
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
-                if e.status == 404:
+                if not e.status == 404:
                     add_span_attributes(span, {"github.label_found": False})
                     set_span_ok(span)
                     return False
........................................................................ [ 30%]
...F
=================================== FAILURES ===================================
________________ TestRepoHasLabel.test_repo_has_label_not_found ________________

self = <tests.test_github_client.TestRepoHasLabel object at 0x7fe5c085dd10>

    def test_repo_has_label_not_found(self):
        """Test repo_has_label returns False when label is missing."""
        from github.GithubException import GithubException
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = GithubException(404, {"message": "Not Found"}, None)
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.repo_has_label(123456, "owner/repo", "missing")
    
>           assert result is False
E           assert None is False

tests/test_github_client.py:1277: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:21:50 [debug    ] Could not verify label missing in owner/repo: 404 {"message": "Not Found"} extra={'repo': 'owner/repo', 'label': 'missing', 'installation_id': 123456, 'error': '404 {"message": "Not Found"}'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_not_found - assert None is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 75 passed, 3 deselected, 1 warning in 2.17s
operator: core/AddNot, occurrence: 12, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1039,7 +1039,7 @@
 
                 for team_ref in allowed_teams:
                     # Extract team slug (handle both "org/team" and "team" formats)
-                    team_slug = team_ref.split("/")[-1] if "/" in team_ref else team_ref
+                    team_slug = team_ref.split("/")[-1] if not "/" in team_ref else team_ref
 
                     try:
                         team = org.get_team_by_slug(team_slug)
......................................................................F
=================================== FAILURES ===================================
________ TestGetUserTeamSlugs.test_get_user_team_slugs_with_org_prefix _________

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7fee3eac1a90>

    def test_get_user_team_slugs_with_org_prefix(self):
        """Test team membership check with org/team format."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_user = Mock()
            mock_team = Mock()
            mock_team.has_in_members.return_value = True
            mock_org = Mock()
            mock_org.get_team_by_slug.return_value = mock_team
    
            mock_github = Mock()
            mock_github.get_organization.return_value = mock_org
            mock_github.get_user.return_value = mock_user
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_user_team_slugs(123456, "acme", "alice", ["acme/release-team"])
    
            # Should extract "release-team" from "acme/release-team"
>           mock_org.get_team_by_slug.assert_called_with("release-team")

tests/test_github_client.py:1077: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_organization().get_team_by_slug' id='140661157869088'>
args = ('release-team',), kwargs = {}, expected = call('release-team')
actual = call('acme/release-team')
_error_message = <function NonCallableMock.assert_called_with.<locals>._error_message at 0x7fee3a5a8880>
cause = None

    def assert_called_with(self, /, *args, **kwargs):
        """assert that the last call was made with the specified arguments.
    
        Raises an AssertionError if the args and keyword args passed in are
        different to the last call to the mock."""
        if self.call_args is None:
            expected = self._format_mock_call_signature(args, kwargs)
            actual = 'not called.'
            error_message = ('expected call not found.\nExpected: %s\n  Actual: %s'
                    % (expected, actual))
            raise AssertionError(error_message)
    
        def _error_message():
            msg = self._format_mock_failure_message(args, kwargs)
            return msg
        expected = self._call_matcher(_Call((args, kwargs), two=True))
        actual = self._call_matcher(self.call_args)
        if actual != expected:
            cause = expected if isinstance(expected, Exception) else None
>           raise AssertionError(_error_message()) from cause
E           AssertionError: expected call not found.
E           Expected: get_team_by_slug('release-team')
E             Actual: get_team_by_slug('acme/release-team')

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:986: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:41:45 [debug    ] User alice is a member of team acme/release-team extra={'org': 'acme', 'username': 'alice', 'team': 'acme/release-team'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_with_org_prefix - AssertionError: expected call not found.
Expected: get_team_by_slug('release-team')
  Actual: get_team_by_slug('acme/release-team')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 70 passed, 3 deselected, 1 warning in 2.21s
operator: core/AddNot, occurrence: 13, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1045,7 +1045,7 @@
                         team = org.get_team_by_slug(team_slug)
                         # Check if user is a member
                         user = client.get_user(username)
-                        if team.has_in_members(user):  # type: ignore[arg-type]
+                        if not team.has_in_members(user):  # type: ignore[arg-type]
                             member_teams.append(team_slug)
                             logger.debug(
                                 "User %s is a member of team %s",
.....................................................................F
=================================== FAILURES ===================================
____________ TestGetUserTeamSlugs.test_get_user_team_slugs_success _____________

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7f1e956c5950>

    def test_get_user_team_slugs_success(self):
        """Test successful team membership check."""
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            # Mock user
            mock_user = Mock()
            mock_user.login = "alice"
    
            # Mock team that has alice as member
            mock_team = Mock()
            mock_team.has_in_members.return_value = True
    
            # Mock org
            mock_org = Mock()
            mock_org.get_team_by_slug.return_value = mock_team
    
            mock_github = Mock()
            mock_github.get_organization.return_value = mock_org
            mock_github.get_user.return_value = mock_user
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_user_team_slugs(
                123456, "acme", "alice", ["release-team", "deploy-team"]
            )
    
>           assert result == ["release-team", "deploy-team"]
E           AssertionError: assert [] == ['release-tea...'deploy-team']
E             
E             Right contains 2 more items, first extra item: 'release-team'
E             
E             Full diff:
E             + []
E             - [
E             -     'release-team',
E             -     'deploy-team',
E             - ]

tests/test_github_client.py:1033: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_success - AssertionError: assert [] == ['release-tea...'deploy-team']
  
  Right contains 2 more items, first extra item: 'release-team'
  
  Full diff:
  + []
  - [
  -     'release-team',
  -     'deploy-team',
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 69 passed, 3 deselected, 1 warning in 2.15s
operator: core/AddNot, occurrence: 14, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1062,7 +1062,7 @@
                         logger.debug(
                             "Could not check team %s membership: %s",
                             team_slug,
-                            e.data.get("message", str(e)) if hasattr(e, "data") else str(e),
+                            e.data.get("message", str(e)) if not hasattr(e, "data") else str(e),
                             extra={
                                 "org": org_name,
                                 "team": team_slug,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceTrueWithFalse, occurrence: 0, definition_name: _ensure_initialized
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -82,7 +82,7 @@
         private_key = self._load_private_key()
         self._auth = Auth.AppAuth(app_id, private_key)
         self._integration = GithubIntegration(auth=self._auth)
-        self._initialized = True
+        self._initialized = False
 
     @property
     def integration(self) -> GithubIntegration:
........................................F
=================================== FAILURES ===================================
____________ TestEnsureInitialized.test_ensure_initialized_success _____________

self = <tests.test_github_client.TestEnsureInitialized object at 0x7fe47c050510>

    def test_ensure_initialized_success(self):
        """Test successful initialization."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth") as mock_auth,
            patch("stampbot.github_client.GithubIntegration") as mock_integration,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            client._ensure_initialized()
    
>           assert client._initialized is True
E           assert False is True
E            +  where False = <stampbot.github_client.GitHubAppClient object at 0x7fe4790b3890>._initialized

tests/test_github_client.py:80: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestEnsureInitialized::test_ensure_initialized_success - assert False is True
 +  where False = <stampbot.github_client.GitHubAppClient object at 0x7fe4790b3890>._initialized
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 40 passed, 3 deselected, 1 warning in 2.11s
operator: core/ReplaceTrueWithFalse, occurrence: 1, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -266,7 +266,7 @@
                         "installation_id": installation_id,
                     },
                 )
-                return True
+                return False
 
             except Exception as e:
                 duration = time.time() - start_time
....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_success _____________________

self = <tests.test_github_client.TestApprovePR object at 0x7fe64bde07d0>

    def test_approve_pr_success(self):
        """Test successful PR approval."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.approve_pr(123456, "owner/repo", 42)
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:313: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:47:09 [info     ] Approved PR #42 in owner/repo  extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 52 passed, 3 deselected, 1 warning in 2.10s
operator: core/ReplaceTrueWithFalse, occurrence: 2, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -408,7 +408,7 @@
                         "review_id": review_id,
                     },
                 )
-                return True
+                return False
 
             except Exception as e:
                 duration = time.time() - start_time
........................................................F
=================================== FAILURES ===================================
______________ TestDismissApproval.test_dismiss_approval_success _______________

self = <tests.test_github_client.TestDismissApproval object at 0x7f93f9d60cd0>

    def test_dismiss_approval_success(self):
        """Test successful approval dismissal."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_review = Mock()
            mock_pr = Mock()
            mock_pr.get_review.return_value = mock_review
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.dismiss_approval(123456, "owner/repo", 42, 999)
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:473: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:33:24 [info     ] Dismissed approval for PR #42 in owner/repo extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'review_id': 999}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestDismissApproval::test_dismiss_approval_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 56 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceTrueWithFalse, occurrence: 3, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -726,7 +726,7 @@
                         "installation_id": installation_id,
                     },
                 )
-                return True
+                return False
 
             except Exception as e:
                 duration = time.time() - start_time
........................................................................ [ 30%]
......F
=================================== FAILURES ===================================
_______ TestCreatePrReviewComment.test_create_pr_review_comment_success ________

self = <tests.test_github_client.TestCreatePrReviewComment object at 0x7f71d4789e50>

    def test_create_pr_review_comment_success(self):
        """Test successful review comment creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_pr_review_comment(
                123456,
                "owner/repo",
                42,
                "Config error",
            )
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:1398: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:14:52 [info     ] Posted config error review on PR #42 in owner/repo extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreatePrReviewComment::test_create_pr_review_comment_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 78 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceTrueWithFalse, occurrence: 4, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -805,7 +805,7 @@
                         "installation_id": installation_id,
                     },
                 )
-                return True
+                return False
 
             except Exception as e:
                 duration = time.time() - start_time
........................................................................ [ 30%]
........F
=================================== FAILURES ===================================
___________ TestCreateIssueComment.test_create_issue_comment_success ___________

self = <tests.test_github_client.TestCreateIssueComment object at 0x7f18c84ca0d0>

    def test_create_issue_comment_success(self):
        """Test successful issue comment creation."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_issue = Mock()
            mock_repo = Mock()
            mock_repo.get_issue.return_value = mock_issue
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_issue_comment(
                123456,
                "owner/repo",
                42,
                "Help text",
            )
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:1487: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:33:50 [info     ] Posted issue comment on #42 in owner/repo extra={'repo': 'owner/repo', 'issue_number': 42, 'installation_id': 123456}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreateIssueComment::test_create_issue_comment_success - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 80 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceTrueWithFalse, occurrence: 5, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -867,7 +867,7 @@
 
                 self._update_rate_limit_metrics(client, installation_id)
 
-                add_span_attributes(span, {"github.label_found": True})
+                add_span_attributes(span, {"github.label_found": False})
                 set_span_ok(span)
                 return True
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceTrueWithFalse, occurrence: 6, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -869,7 +869,7 @@
 
                 add_span_attributes(span, {"github.label_found": True})
                 set_span_ok(span)
-                return True
+                return False
 
             except GithubException as e:
                 duration = time.time() - start_time
........................................................................ [ 30%]
..F
=================================== FAILURES ===================================
__________________ TestRepoHasLabel.test_repo_has_label_true ___________________

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f08563c9bd0>

    def test_repo_has_label_true(self):
        """Test repo_has_label returns True when label exists."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.return_value = Mock()
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=1, limit=2))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.repo_has_label(123456, "owner/repo", "autoapprove")
    
>           assert result is True
E           assert False is True

tests/test_github_client.py:1239: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_true - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 74 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceFalseWithTrue, occurrence: 0, definition_name: __init__
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -60,7 +60,7 @@
         """Initialize GitHub App client (lazy initialization)."""
         self._auth: Auth.AppAuth | None = None
         self._integration: GithubIntegration | None = None
-        self._initialized = False
+        self._initialized = True
 
     def _ensure_initialized(self) -> None:
         """Ensure client is initialized with credentials.
....................................F
=================================== FAILURES ===================================
________ TestGitHubAppClientInit.test_init_creates_uninitialized_client ________

self = <tests.test_github_client.TestGitHubAppClientInit object at 0x7f5f8bae3b10>

    def test_init_creates_uninitialized_client(self):
        """Test that __init__ creates an uninitialized client."""
        from stampbot.github_client import GitHubAppClient
    
        client = GitHubAppClient()
        assert client._auth is None
        assert client._integration is None
>       assert client._initialized is False
E       assert True is False
E        +  where True = <stampbot.github_client.GitHubAppClient object at 0x7f5f875b8550>._initialized

tests/test_github_client.py:24: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGitHubAppClientInit::test_init_creates_uninitialized_client - assert True is False
 +  where True = <stampbot.github_client.GitHubAppClient object at 0x7f5f875b8550>._initialized
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 36 passed, 3 deselected, 1 warning in 2.09s
operator: core/ReplaceFalseWithTrue, occurrence: 1, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -284,7 +284,7 @@
                         "error": _sanitize_error(e),
                     },
                 )
-                return False
+                return True
 
     def get_pr_head_sha(
         self,
.....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_failure _____________________

self = <tests.test_github_client.TestApprovePR object at 0x7fa2f0f14910>

    def test_approve_pr_failure(self):
        """Test PR approval failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_pr.create_review.side_effect = Exception("API Error")
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.approve_pr(123456, "owner/repo", 42)
    
>           assert result is False
E           assert True is False

tests/test_github_client.py:352: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:15:47 [error    ] Failed to approve PR #42 in owner/repo: API Error extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': 'API Error'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_failure - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 53 passed, 3 deselected, 1 warning in 2.12s
operator: core/ReplaceFalseWithTrue, occurrence: 2, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -429,7 +429,7 @@
                         "error": _sanitize_error(e),
                     },
                 )
-                return False
+                return True
 
     def get_repo_file(
         self,
.........................................................F
=================================== FAILURES ===================================
______________ TestDismissApproval.test_dismiss_approval_failure _______________

self = <tests.test_github_client.TestDismissApproval object at 0x7fe776970e10>

    def test_dismiss_approval_failure(self):
        """Test approval dismissal failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_review = Mock()
            mock_review.dismiss.side_effect = Exception("API Error")
            mock_pr = Mock()
            mock_pr.get_review.return_value = mock_review
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.dismiss_approval(123456, "owner/repo", 42, 999)
    
>           assert result is False
E           assert True is False

tests/test_github_client.py:514: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:54:18 [error    ] Failed to dismiss approval for PR #42 in owner/repo: API Error extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': 'API Error'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestDismissApproval::test_dismiss_approval_failure - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 57 passed, 3 deselected, 1 warning in 2.13s
operator: core/ReplaceFalseWithTrue, occurrence: 3, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -747,7 +747,7 @@
                         "error": _sanitize_error(e),
                     },
                 )
-                return False
+                return True
 
     def create_issue_comment(
         self,
........................................................................ [ 30%]
.......F
=================================== FAILURES ===================================
_______ TestCreatePrReviewComment.test_create_pr_review_comment_failure ________

self = <tests.test_github_client.TestCreatePrReviewComment object at 0x7f471f2c9f90>

    def test_create_pr_review_comment_failure(self):
        """Test review comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_pull.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_pr_review_comment(
                123456,
                "owner/repo",
                42,
                "Config error",
            )
    
>           assert result is False
E           assert True is False

tests/test_github_client.py:1440: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:01:04 [warning  ] Failed to post config error review for PR #42 in owner/repo: API Error extra={'repo': 'owner/repo', 'pr_number': 42, 'installation_id': 123456, 'error': 'API Error'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreatePrReviewComment::test_create_pr_review_comment_failure - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 79 passed, 3 deselected, 1 warning in 2.22s
operator: core/ReplaceFalseWithTrue, occurrence: 4, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -828,7 +828,7 @@
                         "error": _sanitize_error(e),
                     },
                 )
-                return False
+                return True
 
     def repo_has_label(
         self,
........................................................................ [ 30%]
.........F
=================================== FAILURES ===================================
___________ TestCreateIssueComment.test_create_issue_comment_failure ___________

self = <tests.test_github_client.TestCreateIssueComment object at 0x7fe8193e2210>

    def test_create_issue_comment_failure(self):
        """Test issue comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_issue.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.create_issue_comment(
                123456,
                "owner/repo",
                42,
                "Help text",
            )
    
>           assert result is False
E           assert True is False

tests/test_github_client.py:1530: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:31:57 [warning  ] Failed to post issue comment on #42 in owner/repo: API Error extra={'repo': 'owner/repo', 'issue_number': 42, 'installation_id': 123456, 'error': 'API Error'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreateIssueComment::test_create_issue_comment_failure - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 81 passed, 3 deselected, 1 warning in 2.17s
operator: core/ReplaceFalseWithTrue, occurrence: 5, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -877,7 +877,7 @@
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
                 if e.status == 404:
-                    add_span_attributes(span, {"github.label_found": False})
+                    add_span_attributes(span, {"github.label_found": True})
                     set_span_ok(span)
                     return False
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceFalseWithTrue, occurrence: 6, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -879,7 +879,7 @@
                 if e.status == 404:
                     add_span_attributes(span, {"github.label_found": False})
                     set_span_ok(span)
-                    return False
+                    return True
 
                 set_span_error(span, e)
                 logger.debug(
........................................................................ [ 30%]
...F
=================================== FAILURES ===================================
________________ TestRepoHasLabel.test_repo_has_label_not_found ________________

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f83eb5c9d10>

    def test_repo_has_label_not_found(self):
        """Test repo_has_label returns False when label is missing."""
        from github.GithubException import GithubException
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = GithubException(404, {"message": "Not Found"}, None)
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.repo_has_label(123456, "owner/repo", "missing")
    
>           assert result is False
E           assert True is False

tests/test_github_client.py:1277: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_not_found - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 75 passed, 3 deselected, 1 warning in 2.16s
operator: core/ReplaceFalseWithTrue, occurrence: 7, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1000,7 +1000,7 @@
                         "error": _sanitize_error(e),
                     },
                 )
-                return False
+                return True
 
     def get_user_team_slugs(
         self,
...................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_error _____________

self = <tests.test_github_client.TestUserHasPermission object at 0x7fb3071748a0>

    def test_user_has_permission_error(self):
        """Test permission check returns False on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.user_has_permission(123456, "owner/repo", "carol", "maintain")
    
>           assert result is False
E           assert True is False

tests/test_github_client.py:941: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:23:56 [warning  ] Failed to check collaborator permission for carol in owner/repo: API Error extra={'repo': 'owner/repo', 'username': 'carol', 'installation_id': 123456, 'error': 'API Error'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_error - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 67 passed, 3 deselected, 1 warning in 2.14s
operator: core/ReplaceAndWithOr, occurrence: 0, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -543,7 +543,7 @@
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state == "APPROVED":
+                    if review.user.login == bot_user or review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
                 duration = time.time() - start_time
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7fdddf4c11d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [123, 456] == [123]
E             
E             Left contains one more item: 456
E             
E             Full diff:
E               [
E                   123,
E             +     456,
E               ]

tests/test_github_client.py:685: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [123, 456] == [123]
  
  Left contains one more item: 456
  
  Full diff:
    [
        123,
  +     456,
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.12s
operator: core/ReplaceAndWithOr, occurrence: 1, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -622,7 +622,7 @@
 
                 bot_reviews: list[BotReview] = []
                 for review in pr.get_reviews():
-                    if review.user.login == bot_user and review.state in (
+                    if review.user.login == bot_user or review.state in (
                         "APPROVED",
                         "DISMISSED",
                     ):
...............................................................F
=================================== FAILURES ===================================
______ TestFindBotApprovalReviews.test_find_bot_approval_reviews_success _______

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7f7633ac1450>

    def test_find_bot_approval_reviews_success(self):
        """Test successful bot approval review state lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            bot_approved_review = Mock()
            bot_approved_review.user.login = "stampbot[bot]"
            bot_approved_review.state = "APPROVED"
            bot_approved_review.id = 123
            bot_approved_review.commit_id = "headsha"
    
            bot_dismissed_review = Mock()
            bot_dismissed_review.user.login = "stampbot[bot]"
            bot_dismissed_review.state = "DISMISSED"
            bot_dismissed_review.id = 124
            bot_dismissed_review.commit_id = "oldsha"
    
            bot_commented_review = Mock()
            bot_commented_review.user.login = "stampbot[bot]"
            bot_commented_review.state = "COMMENTED"
            bot_commented_review.id = 125
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [
                bot_approved_review,
                bot_dismissed_review,
                bot_commented_review,
                other_review,
            ]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
    
>           assert result == [
                {"id": 123, "state": "APPROVED", "commit_id": "headsha"},
                {"id": 124, "state": "DISMISSED", "commit_id": "oldsha"},
            ]
E           AssertionError: assert [{'commit_id'...: 'APPROVED'}] == [{'commit_id'... 'DISMISSED'}]
E             
E             Left contains 2 more items, first extra item: {'commit_id': <Mock name='mock.commit_id' id='140145577230416'>, 'id': 125, 'state': 'COMMENTED'}
E             
E             Full diff:
E               [
E                   {
E                       'commit_id': 'headsha',
E                       'id': 123,
E                       'state': 'APPROVED',
E                   },
E                   {
E                       'commit_id': 'oldsha',
E                       'id': 124,
E                       'state': 'DISMISSED',
E                   },
E             +     {
E             +         'commit_id': <Mock name='mock.commit_id' id='140145577230416'>,
E             +         'id': 125,
E             +         'state': 'COMMENTED',
E             +     },
E             +     {
E             +         'commit_id': <Mock name='mock.commit_id' id='140145577230752'>,
E             +         'id': 456,
E             +         'state': 'APPROVED',
E             +     },
E               ]

tests/test_github_client.py:790: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_success - AssertionError: assert [{'commit_id'...: 'APPROVED'}] == [{'commit_id'... 'DISMISSED'}]
  
  Left contains 2 more items, first extra item: {'commit_id': <Mock name='mock.commit_id' id='140145577230416'>, 'id': 125, 'state': 'COMMENTED'}
  
  Full diff:
    [
        {
            'commit_id': 'headsha',
            'id': 123,
            'state': 'APPROVED',
        },
        {
            'commit_id': 'oldsha',
            'id': 124,
            'state': 'DISMISSED',
        },
  +     {
  +         'commit_id': <Mock name='mock.commit_id' id='140145577230416'>,
  +         'id': 125,
  +         'state': 'COMMENTED',
  +     },
  +     {
  +         'commit_id': <Mock name='mock.commit_id' id='140145577230752'>,
  +         'id': 456,
  +         'state': 'APPROVED',
  +     },
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 63 passed, 3 deselected, 1 warning in 2.16s
operator: core/ReplaceOrWithAnd, occurrence: 0, definition_name: _load_private_key
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -126,7 +126,7 @@
 
             # Security: prevent path traversal by ensuring the path doesn't escape
             # expected directories and doesn't follow symlinks to unexpected locations
-            if ".." in str(key_path) or not os.path.isfile(key_path):
+            if ".." in str(key_path) and not os.path.isfile(key_path):
                 raise ValueError(f"Invalid private key path: {key}")
 
             try:
.............................................F
=================================== FAILURES ===================================
________ TestLoadPrivateKey.test_load_private_key_raises_on_file_error _________

self = <tests.test_github_client.TestLoadPrivateKey object at 0x7f40c2a28640>

    def test_load_private_key_raises_on_file_error(self):
        """Test that _load_private_key raises when file doesn't exist."""
        with patch("stampbot.github_client.settings") as mock_settings:
            mock_settings.private_key = "/nonexistent/path/to/key.pem"
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            with pytest.raises(ValueError, match="Invalid private key path"):
>               client._load_private_key()

tests/test_github_client.py:148: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f40bf92f2f0>

    def _load_private_key(self) -> str:
        """Load private key from settings or file.
    
        Returns:
            Private key contents as PEM string.
    
        Raises:
            RuntimeError: If private key is not configured.
            ValueError: If private key is not valid PEM format.
            OSError: If private key file cannot be read.
        """
        key: str | None = settings.private_key
    
        if key is None:
            raise RuntimeError("Private key not configured")
    
        # If it looks like PEM content, use directly
        if key.startswith("-----BEGIN"):
            pem_content = key
        else:
            # Treat as file path - read the file
            import os
            from pathlib import Path
    
            key_path = Path(key).resolve()
    
            # Security: prevent path traversal by ensuring the path doesn't escape
            # expected directories and doesn't follow symlinks to unexpected locations
            if ".." in str(key_path) and not os.path.isfile(key_path):
                raise ValueError(f"Invalid private key path: {key}")
    
            try:
>               with open(key_path) as f:
                     ^^^^^^^^^^^^^^
E               FileNotFoundError: [Errno 2] No such file or directory: '/nonexistent/path/to/key.pem'

stampbot/github_client.py:133: FileNotFoundError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:46:47 [error    ] Failed to read private key from file: [Errno 2] No such file or directory: '/nonexistent/path/to/key.pem'
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestLoadPrivateKey::test_load_private_key_raises_on_file_error - FileNotFoundError: [Errno 2] No such file or directory: '/nonexistent/path/to/key.pem'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 45 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceOrWithAnd, occurrence: 1, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -456,7 +456,7 @@
             {
                 "github.repo": repo_full_name,
                 "github.file_path": file_path,
-                "github.ref": ref or "default",
+                "github.ref": ref and "default",
                 "github.installation_id": installation_id,
             },
         ) as span:
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceContinueWithBreak, occurrence: 0, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1069,7 +1069,7 @@
                                 "username": username,
                             },
                         )
-                        continue
+                        break
 
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ExceptionReplacer, occurrence: 0, definition_name: _load_private_key
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -132,7 +132,7 @@
             try:
                 with open(key_path) as f:
                     pem_content = f.read()
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 logger.error("Failed to read private key from file: %s", e)
                 raise
 
..............................................F
=================================== FAILURES ===================================
________ TestLoadPrivateKey.test_load_private_key_raises_on_read_error _________

self = <stampbot.github_client.GitHubAppClient object at 0x7fa02666f2f0>

    def _load_private_key(self) -> str:
        """Load private key from settings or file.
    
        Returns:
            Private key contents as PEM string.
    
        Raises:
            RuntimeError: If private key is not configured.
            ValueError: If private key is not valid PEM format.
            OSError: If private key file cannot be read.
        """
        key: str | None = settings.private_key
    
        if key is None:
            raise RuntimeError("Private key not configured")
    
        # If it looks like PEM content, use directly
        if key.startswith("-----BEGIN"):
            pem_content = key
        else:
            # Treat as file path - read the file
            import os
            from pathlib import Path
    
            key_path = Path(key).resolve()
    
            # Security: prevent path traversal by ensuring the path doesn't escape
            # expected directories and doesn't follow symlinks to unexpected locations
            if ".." in str(key_path) or not os.path.isfile(key_path):
                raise ValueError(f"Invalid private key path: {key}")
    
            try:
>               with open(key_path) as f:
                     ^^^^^^^^^^^^^^

stampbot/github_client.py:133: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='open' id='140325797659040'>
args = (PosixPath('/tmp/pytest-of-runner/pytest-579/test_load_private_key_raises_o0/private-key.pem'),)
kwargs = {}, effect = PermissionError('Access denied')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               PermissionError: Access denied

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: PermissionError

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestLoadPrivateKey object at 0x7fa029764ef0>
tmp_path = PosixPath('/tmp/pytest-of-runner/pytest-579/test_load_private_key_raises_o0')

    def test_load_private_key_raises_on_read_error(self, tmp_path):
        """Test that _load_private_key raises when file read fails."""
        key_file = tmp_path / "private-key.pem"
        key_file.write_text("dummy")
    
        with patch("stampbot.github_client.settings") as mock_settings:
            mock_settings.private_key = str(key_file)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
    
            # Mock open to raise an exception after the file existence check passes
            with patch("builtins.open", side_effect=PermissionError("Access denied")):
                with pytest.raises(PermissionError, match="Access denied"):
>                   client._load_private_key()

tests/test_github_client.py:165: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fa02666f2f0>

    def _load_private_key(self) -> str:
        """Load private key from settings or file.
    
        Returns:
            Private key contents as PEM string.
    
        Raises:
            RuntimeError: If private key is not configured.
            ValueError: If private key is not valid PEM format.
            OSError: If private key file cannot be read.
        """
        key: str | None = settings.private_key
    
        if key is None:
            raise RuntimeError("Private key not configured")
    
        # If it looks like PEM content, use directly
        if key.startswith("-----BEGIN"):
            pem_content = key
        else:
            # Treat as file path - read the file
            import os
            from pathlib import Path
    
            key_path = Path(key).resolve()
    
            # Security: prevent path traversal by ensuring the path doesn't escape
            # expected directories and doesn't follow symlinks to unexpected locations
            if ".." in str(key_path) or not os.path.isfile(key_path):
                raise ValueError(f"Invalid private key path: {key}")
    
            try:
                with open(key_path) as f:
                    pem_content = f.read()
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/github_client.py:135: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestLoadPrivateKey::test_load_private_key_raises_on_read_error - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 46 passed, 3 deselected, 1 warning in 2.30s
operator: core/ExceptionReplacer, occurrence: 1, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -184,7 +184,7 @@
                 set_span_ok(span)
                 return client
 
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                 github_api_requests_total.labels(operation="get_token", status="failure").inc()
.................................................F
=================================== FAILURES ===================================
________ TestGetInstallationClient.test_get_installation_client_failure ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f3371fdb6c0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
>               auth = self.integration.get_access_token(installation_id)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:164: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='GithubIntegration().get_access_token' id='139858886527360'>
args = (123456,), kwargs = {}, effect = Exception('Token exchange failed')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Token exchange failed

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f3373810410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            with pytest.raises(Exception, match="Token exchange failed"):
>               client._get_installation_client(123456)

tests/test_github_client.py:240: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f3371fdb6c0>
installation_id = 123456

    def _get_installation_client(self, installation_id: int) -> Github:
        """Get authenticated GitHub client for an installation.
    
        Args:
            installation_id: GitHub App installation ID.
    
        Returns:
            Authenticated Github client instance with timeout and retry configured.
    
        Raises:
            github.GithubException: If token exchange fails.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_installation_token",
            {"github.installation_id": installation_id},
        ) as span:
            try:
                auth = self.integration.get_access_token(installation_id)
    
                # Configure retry with exponential backoff
                retry = Retry(
                    total=GITHUB_API_RETRY_TOTAL,
                    backoff_factor=GITHUB_API_RETRY_BACKOFF,
                    status_forcelist=[500, 502, 503, 504],
                    allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                )
    
                client = Github(
                    auth=Auth.Token(auth.token),
                    timeout=GITHUB_API_TIMEOUT,
                    retry=retry,
                )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_token").observe(duration)
                github_api_requests_total.labels(operation="get_token", status="success").inc()
    
                set_span_ok(span)
                return client
    
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/github_client.py:187: NameError

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetInstallationClient object at 0x7f3373810410>

    def test_get_installation_client_failure(self):
        """Test installation client creation failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_integration.get_access_token.side_effect = Exception("Token exchange failed")
            mock_integration_cls.return_value = mock_integration
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           with pytest.raises(Exception, match="Token exchange failed"):
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           AssertionError: Regex pattern did not match.
E             Expected regex: 'Token exchange failed'
E             Actual message: "name 'CosmicRayTestingException' is not defined"

tests/test_github_client.py:239: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetInstallationClient::test_get_installation_client_failure - AssertionError: Regex pattern did not match.
  Expected regex: 'Token exchange failed'
  Actual message: "name 'CosmicRayTestingException' is not defined"
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 49 passed, 3 deselected, 1 warning in 2.28s
operator: core/ExceptionReplacer, occurrence: 2, definition_name: _update_rate_limit_metrics
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -206,7 +206,7 @@
             github_api_rate_limit_limit.labels(installation_id=str(installation_id)).set(
                 rate_limit.core.limit  # type: ignore[attr-defined]
             )
-        except Exception:
+        except CosmicRayTestingException:
             # Don't fail operations due to rate limit metric errors
             pass
 
...................................................F
=================================== FAILURES ===================================
_ TestUpdateRateLimitMetrics.test_update_rate_limit_metrics_handles_exception __

self = <stampbot.github_client.GitHubAppClient object at 0x7f2b0b9a0b90>
client = <Mock id='139822836618576'>, installation_id = 123456

    def _update_rate_limit_metrics(self, client: Github, installation_id: int) -> None:
        """Update rate limit metrics from GitHub client.
    
        Args:
            client: Authenticated GitHub client.
            installation_id: GitHub App installation ID for metric labels.
        """
        try:
>           rate_limit = client.get_rate_limit()
                         ^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:202: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='mock.get_rate_limit' id='139822836618912'>, args = ()
kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestUpdateRateLimitMetrics object at 0x7f2b0ee60690>

    def test_update_rate_limit_metrics_handles_exception(self):
        """Test that rate limit metrics errors are silently ignored."""
        from stampbot.github_client import GitHubAppClient
    
        client = GitHubAppClient()
    
        mock_github_client = Mock()
        mock_github_client.get_rate_limit.side_effect = Exception("API Error")
    
        # Should not raise - errors are silently ignored
>       client._update_rate_limit_metrics(mock_github_client, 123456)

tests/test_github_client.py:271: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f2b0b9a0b90>
client = <Mock id='139822836618576'>, installation_id = 123456

    def _update_rate_limit_metrics(self, client: Github, installation_id: int) -> None:
        """Update rate limit metrics from GitHub client.
    
        Args:
            client: Authenticated GitHub client.
            installation_id: GitHub App installation ID for metric labels.
        """
        try:
            rate_limit = client.get_rate_limit()
            github_api_rate_limit_remaining.labels(installation_id=str(installation_id)).set(
                rate_limit.core.remaining  # type: ignore[attr-defined]
            )
            github_api_rate_limit_limit.labels(installation_id=str(installation_id)).set(
                rate_limit.core.limit  # type: ignore[attr-defined]
            )
>       except CosmicRayTestingException:
               ^^^^^^^^^^^^^^^^^^^^^^^^^
E       NameError: name 'CosmicRayTestingException' is not defined

stampbot/github_client.py:209: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUpdateRateLimitMetrics::test_update_rate_limit_metrics_handles_exception - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 51 passed, 3 deselected, 1 warning in 2.26s
operator: core/ExceptionReplacer, occurrence: 3, definition_name: approve_pr
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -268,7 +268,7 @@
                 )
                 return True
 
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                 github_api_requests_total.labels(operation="approve", status="failure").inc()
.....................................................F
=================================== FAILURES ===================================
____________________ TestApprovePR.test_approve_pr_failure _____________________

self = <stampbot.github_client.GitHubAppClient object at 0x7fdd3ab0a620>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
comment = 'Auto-approved by Stampbot'

    def approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str = "Auto-approved by Stampbot",
    ) -> bool:
        """Approve a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            comment: Review comment
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Create approval review
>               pr.create_review(
                    body=comment,
                    event="APPROVE",
                )

stampbot/github_client.py:247: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull().create_review' id='140588149295824'>
args = (), kwargs = {'body': 'Auto-approved by Stampbot', 'event': 'APPROVE'}
effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestApprovePR object at 0x7fdd3f0c0910>

    def test_approve_pr_failure(self):
        """Test PR approval failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_pr = Mock()
            mock_pr.create_review.side_effect = Exception("API Error")
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.approve_pr(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:350: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fdd3ab0a620>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
comment = 'Auto-approved by Stampbot'

    def approve_pr(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        comment: str = "Auto-approved by Stampbot",
    ) -> bool:
        """Approve a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            comment: Review comment
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.approve_pr",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Create approval review
                pr.create_review(
                    body=comment,
                    event="APPROVE",
                )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="approve").observe(duration)
                github_api_requests_total.labels(operation="approve", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "approved"})
                set_span_ok(span)
    
                logger.info(
                    f"Approved PR #{pr_number} in {repo_full_name}",
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/github_client.py:271: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestApprovePR::test_approve_pr_failure - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 53 passed, 3 deselected, 1 warning in 2.24s
operator: core/ExceptionReplacer, occurrence: 4, definition_name: get_pr_head_sha
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -329,7 +329,7 @@
 
                 return head_sha
 
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                 github_api_requests_total.labels(operation="get_pull", status="failure").inc()
.......................................................F
=================================== FAILURES ===================================
_________ TestGetPRHeadSHA.test_get_pr_head_sha_returns_none_on_error __________

self = <stampbot.github_client.GitHubAppClient object at 0x7f68417c2530>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def get_pr_head_sha(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> str | None:
        """Get the current head SHA for a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Current pull request head SHA, or None on error.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_pr_head_sha",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:317: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140085750155984'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetPRHeadSHA object at 0x7f6845a14b90>

    def test_get_pr_head_sha_returns_none_on_error(self):
        """Test PR head SHA lookup returns None on API errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_pr_head_sha(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:427: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f68417c2530>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def get_pr_head_sha(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> str | None:
        """Get the current head SHA for a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Current pull request head SHA, or None on error.
        """
        start_time = time.time()
    
        with create_span(
            "github.get_pr_head_sha",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
                head_sha: str = pr.head.sha
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_pull").observe(duration)
                github_api_requests_total.labels(operation="get_pull", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.head_sha": head_sha})
                set_span_ok(span)
    
                return head_sha
    
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/github_client.py:332: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetPRHeadSHA::test_get_pr_head_sha_returns_none_on_error - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 55 passed, 3 deselected, 1 warning in 2.26s
operator: core/ExceptionReplacer, occurrence: 5, definition_name: dismiss_approval
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -410,7 +410,7 @@
                 )
                 return True
 
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                 github_api_requests_total.labels(operation="dismiss", status="failure").inc()
.........................................................F
=================================== FAILURES ===================================
______________ TestDismissApproval.test_dismiss_approval_failure _______________

self = <stampbot.github_client.GitHubAppClient object at 0x7f0f21ce7a50>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
review_id = 999, message = 'Approval dismissed by Stampbot'

    def dismiss_approval(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        review_id: int,
        message: str = "Approval dismissed by Stampbot",
    ) -> bool:
        """Dismiss a pull request approval.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            review_id: Review ID to dismiss
            message: Dismissal message
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.dismiss_approval",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.review_id": review_id,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get the review and dismiss it
                review = pr.get_review(review_id)
>               review.dismiss(message)

stampbot/github_client.py:391: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull().get_review().dismiss' id='139702949781456'>
args = ('Approval dismissed by Stampbot',), kwargs = {}
effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestDismissApproval object at 0x7f0f25144e10>

    def test_dismiss_approval_failure(self):
        """Test approval dismissal failure."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_review = Mock()
            mock_review.dismiss.side_effect = Exception("API Error")
            mock_pr = Mock()
            mock_pr.get_review.return_value = mock_review
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.dismiss_approval(123456, "owner/repo", 42, 999)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:512: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f0f21ce7a50>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
review_id = 999, message = 'Approval dismissed by Stampbot'

    def dismiss_approval(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        review_id: int,
        message: str = "Approval dismissed by Stampbot",
    ) -> bool:
        """Dismiss a pull request approval.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            review_id: Review ID to dismiss
            message: Dismissal message
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.dismiss_approval",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.review_id": review_id,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get the review and dismiss it
                review = pr.get_review(review_id)
                review.dismiss(message)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="dismiss").observe(duration)
                github_api_requests_total.labels(operation="dismiss", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "dismissed"})
                set_span_ok(span)
    
                logger.info(
                    f"Dismissed approval for PR #{pr_number} in {repo_full_name}",
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                        "review_id": review_id,
                    },
                )
                return True
    
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/github_client.py:413: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestDismissApproval::test_dismiss_approval_failure - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 57 passed, 3 deselected, 1 warning in 2.27s
operator: core/ExceptionReplacer, occurrence: 6, definition_name: get_repo_file
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -486,7 +486,7 @@
 
                 return content.decoded_content.decode("utf-8")
 
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                 github_api_requests_total.labels(operation="get_file", status="not_found").inc()
............................................................F
=================================== FAILURES ===================================
___________ TestGetRepoFile.test_get_repo_file_returns_none_on_error ___________

self = <stampbot.github_client.GitHubAppClient object at 0x7f657d422740>
installation_id = 123456, repo_full_name = 'owner/repo'
file_path = 'nonexistent.toml', ref = None

    def get_repo_file(
        self,
        installation_id: int,
        repo_full_name: str,
        file_path: str,
        ref: str | None = None,
    ) -> str | None:
        """Get file content from repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            file_path: Path to file in repository
            ref: Git reference (branch, tag, commit). Defaults to default branch
    
        Returns:
            File content as string, or None if not found
        """
        start_time = time.time()
    
        with create_span(
            "github.get_file",
            {
                "github.repo": repo_full_name,
                "github.file_path": file_path,
                "github.ref": ref or "default",
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
>               content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:467: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_contents' id='140073800520032'>
args = ('nonexistent.toml',), kwargs = {'ref': None}
effect = Exception('File not found')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: File not found

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetRepoFile object at 0x7f657d428770>

    def test_get_repo_file_returns_none_on_error(self):
        """Test that get_repo_file returns None when file not found."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_contents.side_effect = Exception("File not found")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_repo_file(123456, "owner/repo", "nonexistent.toml")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:628: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f657d422740>
installation_id = 123456, repo_full_name = 'owner/repo'
file_path = 'nonexistent.toml', ref = None

    def get_repo_file(
        self,
        installation_id: int,
        repo_full_name: str,
        file_path: str,
        ref: str | None = None,
    ) -> str | None:
        """Get file content from repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            file_path: Path to file in repository
            ref: Git reference (branch, tag, commit). Defaults to default branch
    
        Returns:
            File content as string, or None if not found
        """
        start_time = time.time()
    
        with create_span(
            "github.get_file",
            {
                "github.repo": repo_full_name,
                "github.file_path": file_path,
                "github.ref": ref or "default",
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
                content = repo.get_contents(file_path, ref=ref)  # type: ignore[arg-type]
                if isinstance(content, list):
                    duration = time.time() - start_time
                    github_api_request_duration_seconds.labels(operation="get_file").observe(
                        duration
                    )
                    github_api_requests_total.labels(operation="get_file", status="not_found").inc()
                    add_span_attributes(span, {"github.result": "not_found"})
                    set_span_ok(span)
                    return None
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_file").observe(duration)
                github_api_requests_total.labels(operation="get_file", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "found"})
                set_span_ok(span)
    
                return content.decoded_content.decode("utf-8")
    
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/github_client.py:489: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetRepoFile::test_get_repo_file_returns_none_on_error - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 60 passed, 3 deselected, 1 warning in 2.31s
operator: core/ExceptionReplacer, occurrence: 7, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -561,7 +561,7 @@
 
                 return bot_review_ids
 
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
..............................................................F
=================================== FAILURES ===================================
_______ TestFindBotReviews.test_find_bot_reviews_returns_empty_on_error ________

self = <stampbot.github_client.GitHubAppClient object at 0x7fbe377e4830>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[int]:
        """Find all reviews created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            List of review IDs created by the bot
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:535: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140454949696384'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestFindBotReviews object at 0x7fbe3ba15310>

    def test_find_bot_reviews_returns_empty_on_error(self):
        """Test that find_bot_reviews returns empty list on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.find_bot_reviews(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:717: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fbe377e4830>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[int]:
        """Find all reviews created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            List of review IDs created by the bot
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get bot user via JWT-authenticated integration (installation tokens
                # cannot call GET /user, which is restricted by GitHub Apps integration)
                app_info = self.integration.get_app()
                bot_user = f"{app_info.slug}[bot]"
    
                # Find all reviews by bot that are approvals
                bot_review_ids = []
                for review in pr.get_reviews():
                    if review.user.login == bot_user and review.state == "APPROVED":
                        bot_review_ids.append(review.id)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                    duration
                )
                github_api_requests_total.labels(operation="find_reviews", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span, {"github.reviews_found": len(bot_review_ids), "github.bot_user": bot_user}
                )
                set_span_ok(span)
    
                return bot_review_ids
    
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/github_client.py:564: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_returns_empty_on_error - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 62 passed, 3 deselected, 1 warning in 2.28s
operator: core/ExceptionReplacer, occurrence: 8, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -649,7 +649,7 @@
 
                 return bot_reviews
 
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                     duration
................................................................F
=================================== FAILURES ===================================
_ TestFindBotApprovalReviews.test_find_bot_approval_reviews_returns_empty_on_error _

self = <stampbot.github_client.GitHubAppClient object at 0x7fbdfb37fe30>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_approval_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[BotReview]:
        """Find approval review states created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Review state details for bot approval reviews.
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_approval_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
>               repo = client.get_repo(repo_full_name)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:615: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo' id='140453940350320'>
args = ('owner/repo',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7fbdff719590>

    def test_find_bot_approval_reviews_returns_empty_on_error(self):
        """Test that find_bot_approval_reviews returns empty list on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_repo.side_effect = Exception("API Error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:825: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fbdfb37fe30>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42

    def find_bot_approval_reviews(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
    ) -> list[BotReview]:
        """Find approval review states created by this bot on a PR.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
    
        Returns:
            Review state details for bot approval reviews.
        """
        start_time = time.time()
    
        with create_span(
            "github.find_bot_approval_reviews",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                # Get bot user via JWT-authenticated integration (installation tokens
                # cannot call GET /user, which is restricted by GitHub Apps integration)
                app_info = self.integration.get_app()
                bot_user = f"{app_info.slug}[bot]"
    
                bot_reviews: list[BotReview] = []
                for review in pr.get_reviews():
                    if review.user.login == bot_user and review.state in (
                        "APPROVED",
                        "DISMISSED",
                    ):
                        bot_reviews.append(
                            {
                                "id": review.id,
                                "state": review.state,
                                "commit_id": getattr(review, "commit_id", None),
                            }
                        )
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="find_reviews").observe(
                    duration
                )
                github_api_requests_total.labels(operation="find_reviews", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span, {"github.reviews_found": len(bot_reviews), "github.bot_user": bot_user}
                )
                set_span_ok(span)
    
                return bot_reviews
    
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/github_client.py:652: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_returns_empty_on_error - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 64 passed, 3 deselected, 1 warning in 2.28s
operator: core/ExceptionReplacer, occurrence: 9, definition_name: create_pr_review_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -728,7 +728,7 @@
                 )
                 return True
 
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                 github_api_requests_total.labels(operation="comment", status="failure").inc()
........................................................................ [ 30%]
.......F
=================================== FAILURES ===================================
_______ TestCreatePrReviewComment.test_create_pr_review_comment_failure ________

self = <stampbot.github_client.GitHubAppClient object at 0x7fc9f93142f0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
message = 'Config error'

    def create_pr_review_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
    ) -> bool:
        """Create a comment review on a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            message: Review comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_review_comment",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               pr = repo.get_pull(pr_number)
                     ^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:706: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_pull' id='140505447102320'>
args = (42,), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestCreatePrReviewComment object at 0x7fc9fd7a1f90>

    def test_create_pr_review_comment_failure(self):
        """Test review comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_pull.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.create_pr_review_comment(
                123456,
                "owner/repo",
                42,
                "Config error",
            )

tests/test_github_client.py:1433: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fc9f93142f0>
installation_id = 123456, repo_full_name = 'owner/repo', pr_number = 42
message = 'Config error'

    def create_pr_review_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        pr_number: int,
        message: str,
    ) -> bool:
        """Create a comment review on a pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            pr_number: Pull request number
            message: Review comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_review_comment",
            {
                "github.repo": repo_full_name,
                "github.pr_number": pr_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                pr = repo.get_pull(pr_number)
    
                pr.create_review(body=message, event="COMMENT")
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="comment").observe(duration)
                github_api_requests_total.labels(operation="comment", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "commented"})
                set_span_ok(span)
    
                logger.info(
                    "Posted config error review on PR #%d in %s",
                    pr_number,
                    repo_full_name,
                    extra={
                        "repo": repo_full_name,
                        "pr_number": pr_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/github_client.py:731: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreatePrReviewComment::test_create_pr_review_comment_failure - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 79 passed, 3 deselected, 1 warning in 2.31s
operator: core/ExceptionReplacer, occurrence: 10, definition_name: create_issue_comment
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -807,7 +807,7 @@
                 )
                 return True
 
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                     duration
........................................................................ [ 30%]
.........F
=================================== FAILURES ===================================
___________ TestCreateIssueComment.test_create_issue_comment_failure ___________

self = <stampbot.github_client.GitHubAppClient object at 0x7fe19931acf0>
installation_id = 123456, repo_full_name = 'owner/repo', issue_number = 42
message = 'Help text'

    def create_issue_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        issue_number: int,
        message: str,
    ) -> bool:
        """Create a comment on an issue or pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            issue_number: Issue or pull request number
            message: Comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_issue_comment",
            {
                "github.repo": repo_full_name,
                "github.issue_number": issue_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               issue = repo.get_issue(issue_number)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:783: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_issue' id='140606916422224'>
args = (42,), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestCreateIssueComment object at 0x7fe19d9c2210>

    def test_create_issue_comment_failure(self):
        """Test issue comment creation handles errors."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_issue.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.create_issue_comment(
                123456,
                "owner/repo",
                42,
                "Help text",
            )

tests/test_github_client.py:1523: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fe19931acf0>
installation_id = 123456, repo_full_name = 'owner/repo', issue_number = 42
message = 'Help text'

    def create_issue_comment(
        self,
        installation_id: int,
        repo_full_name: str,
        issue_number: int,
        message: str,
    ) -> bool:
        """Create a comment on an issue or pull request.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            issue_number: Issue or pull request number
            message: Comment body
    
        Returns:
            True if successful, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.create_issue_comment",
            {
                "github.repo": repo_full_name,
                "github.issue_number": issue_number,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                issue = repo.get_issue(issue_number)
    
                issue.create_comment(message)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="issue_comment").observe(
                    duration
                )
                github_api_requests_total.labels(operation="issue_comment", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.result": "commented"})
                set_span_ok(span)
    
                logger.info(
                    "Posted issue comment on #%d in %s",
                    issue_number,
                    repo_full_name,
                    extra={
                        "repo": repo_full_name,
                        "issue_number": issue_number,
                        "installation_id": installation_id,
                    },
                )
                return True
    
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/github_client.py:810: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestCreateIssueComment::test_create_issue_comment_failure - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 81 passed, 3 deselected, 1 warning in 2.32s
operator: core/ExceptionReplacer, occurrence: 11, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -871,7 +871,7 @@
                 set_span_ok(span)
                 return True
 
-            except GithubException as e:
+            except CosmicRayTestingException as e:
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
........................................................................ [ 30%]
...F
=================================== FAILURES ===================================
________________ TestRepoHasLabel.test_repo_has_label_not_found ________________

self = <stampbot.github_client.GitHubAppClient object at 0x7fe4580dd9d0>
installation_id = 123456, repo_full_name = 'owner/repo', label_name = 'missing'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               repo.get_label(label_name)

stampbot/github_client.py:862: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_label' id='140618707785712'>
args = ('missing',), kwargs = {}
effect = GithubException(404 {"message": "Not Found"})

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               github.GithubException.GithubException: 404 {"message": "Not Found"}

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: GithubException

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestRepoHasLabel object at 0x7fe45cca1d10>

    def test_repo_has_label_not_found(self):
        """Test repo_has_label returns False when label is missing."""
        from github.GithubException import GithubException
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = GithubException(404, {"message": "Not Found"}, None)
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.repo_has_label(123456, "owner/repo", "missing")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1275: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fe4580dd9d0>
installation_id = 123456, repo_full_name = 'owner/repo', label_name = 'missing'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                repo.get_label(label_name)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.label_found": True})
                set_span_ok(span)
                return True
    
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/github_client.py:874: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_not_found - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 75 passed, 3 deselected, 1 warning in 2.31s
operator: core/ExceptionReplacer, occurrence: 12, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -896,7 +896,7 @@
                 )
                 return None
 
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
........................................................................ [ 30%]
.....F
=================================== FAILURES ===================================
__________________ TestRepoHasLabel.test_repo_has_label_error __________________

self = <stampbot.github_client.GitHubAppClient object at 0x7fe1c3ab9cd0>
installation_id = 123456, repo_full_name = 'owner/repo'
label_name = 'autoapprove'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
>               repo.get_label(label_name)

stampbot/github_client.py:862: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_label' id='140607626601408'>
args = ('autoapprove',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestRepoHasLabel object at 0x7fe1c7c70e90>

    def test_repo_has_label_error(self):
        """Test repo_has_label returns None on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.repo_has_label(123456, "owner/repo", "autoapprove")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1349: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7fe1c3ab9cd0>
installation_id = 123456, repo_full_name = 'owner/repo'
label_name = 'autoapprove'

    def repo_has_label(
        self,
        installation_id: int,
        repo_full_name: str,
        label_name: str,
    ) -> bool | None:
        """Check whether a repository has a label.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            label_name: Label name to look up
    
        Returns:
            True if label exists, False if not found, None if unknown due to error
        """
        start_time = time.time()
    
        with create_span(
            "github.get_label",
            {
                "github.repo": repo_full_name,
                "github.label": label_name,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
                repo.get_label(label_name)
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(span, {"github.label_found": True})
                set_span_ok(span)
                return True
    
            except GithubException as e:
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                github_api_requests_total.labels(operation="get_label", status="failure").inc()
    
                if e.status == 404:
                    add_span_attributes(span, {"github.label_found": False})
                    set_span_ok(span)
                    return False
    
                set_span_error(span, e)
                logger.debug(
                    "Could not verify label %s in %s: %s",
                    label_name,
                    repo_full_name,
                    _sanitize_error(e),
                    extra={
                        "repo": repo_full_name,
                        "label": label_name,
                        "installation_id": installation_id,
                        "error": _sanitize_error(e),
                    },
                )
                return None
    
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/github_client.py:899: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_error - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 77 passed, 3 deselected, 1 warning in 2.37s
operator: core/ExceptionReplacer, occurrence: 13, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -954,7 +954,7 @@
                 try:
                     permission_index = permission_order.index(permission)
                     required_index = permission_order.index(required_permission)
-                except ValueError:
+                except CosmicRayTestingException:
                     permission_index = -1
                     required_index = 99
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ExceptionReplacer, occurrence: 14, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -979,7 +979,7 @@
 
                 return has_permission
 
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="get_permission").observe(
                     duration
...................................................................F
=================================== FAILURES ===================================
_____________ TestUserHasPermission.test_user_has_permission_error _____________

self = <stampbot.github_client.GitHubAppClient object at 0x7f7d06647170>
installation_id = 123456, repo_full_name = 'owner/repo', username = 'carol'
required_permission = 'maintain'

    def user_has_permission(
        self,
        installation_id: int,
        repo_full_name: str,
        username: str,
        required_permission: str,
    ) -> bool:
        """Check whether a user has required access to a repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            username: GitHub username to check
            required_permission: Minimum required repository permission
    
        Returns:
            True if user meets or exceeds required permission, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.get_collaborator_permission",
            {
                "github.repo": repo_full_name,
                "github.username": username,
                "github.required_permission": required_permission,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
>               permission = repo.get_collaborator_permission(username)
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:952: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_repo().get_collaborator_permission' id='140174954668320'>
args = ('carol',), kwargs = {}, effect = Exception('API Error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API Error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestUserHasPermission object at 0x7f7d0a8548a0>

    def test_user_has_permission_error(self):
        """Test permission check returns False on error."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_collaborator_permission.side_effect = Exception("API Error")
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.user_has_permission(123456, "owner/repo", "carol", "maintain")
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:939: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f7d06647170>
installation_id = 123456, repo_full_name = 'owner/repo', username = 'carol'
required_permission = 'maintain'

    def user_has_permission(
        self,
        installation_id: int,
        repo_full_name: str,
        username: str,
        required_permission: str,
    ) -> bool:
        """Check whether a user has required access to a repository.
    
        Args:
            installation_id: GitHub App installation ID
            repo_full_name: Repository full name (owner/repo)
            username: GitHub username to check
            required_permission: Minimum required repository permission
    
        Returns:
            True if user meets or exceeds required permission, False otherwise
        """
        start_time = time.time()
    
        with create_span(
            "github.get_collaborator_permission",
            {
                "github.repo": repo_full_name,
                "github.username": username,
                "github.required_permission": required_permission,
                "github.installation_id": installation_id,
            },
        ) as span:
            try:
                client = self._get_installation_client(installation_id)
                repo = client.get_repo(repo_full_name)
    
                permission = repo.get_collaborator_permission(username)
                permission_order = ["none", "read", "triage", "write", "maintain", "admin"]
                try:
                    permission_index = permission_order.index(permission)
                    required_index = permission_order.index(required_permission)
                except ValueError:
                    permission_index = -1
                    required_index = 99
    
                has_permission = permission_index >= required_index
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_permission").observe(
                    duration
                )
                github_api_requests_total.labels(operation="get_permission", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span,
                    {
                        "github.permission": permission,
                        "github.has_permission": has_permission,
                    },
                )
                set_span_ok(span)
    
                return has_permission
    
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/github_client.py:982: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestUserHasPermission::test_user_has_permission_error - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 67 passed, 3 deselected, 1 warning in 2.31s
operator: core/ExceptionReplacer, occurrence: 15, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1057,7 +1057,7 @@
                                     "team": team_slug,
                                 },
                             )
-                    except GithubException as e:
+                    except CosmicRayTestingException as e:
                         # Team not found or no access - skip silently
                         logger.debug(
                             "Could not check team %s membership: %s",
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ExceptionReplacer, occurrence: 16, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1090,7 +1090,7 @@
 
                 return member_teams
 
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 duration = time.time() - start_time
                 github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                     duration
........................................................................ [ 30%]
.F
=================================== FAILURES ===================================
_______ TestGetUserTeamSlugs.test_get_user_team_slugs_general_exception ________

self = <stampbot.github_client.GitHubAppClient object at 0x7f1d623c4830>
installation_id = 123456, org_name = 'acme', username = 'alice'
allowed_teams = ['release-team']

    def get_user_team_slugs(
        self,
        installation_id: int,
        org_name: str,
        username: str,
        allowed_teams: list[str],
    ) -> list[str]:
        """Get team slugs the user is a member of from the allowed teams list.
    
        Args:
            installation_id: GitHub App installation ID
            org_name: Organization name
            username: GitHub username to check
            allowed_teams: List of team slugs to check (can be "org/team" or just "team")
    
        Returns:
            List of team slugs the user is a member of
        """
        start_time = time.time()
    
        with create_span(
            "github.get_user_team_slugs",
            {
                "github.org": org_name,
                "github.username": username,
                "github.installation_id": installation_id,
                "github.teams_to_check": len(allowed_teams),
            },
        ) as span:
            member_teams: list[str] = []
    
            try:
                client = self._get_installation_client(installation_id)
>               org = client.get_organization(org_name)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/github_client.py:1038: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1176: in __call__
    return self._mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1180: in _mock_call
    return self._execute_mock_call(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_organization' id='139764178346944'>
args = ('acme',), kwargs = {}, effect = Exception('Network error')

    def _execute_mock_call(self, /, *args, **kwargs):
        # separate from _increment_mock_call so that awaited functions are
        # executed separately from their call, also AsyncMock overrides this method
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Network error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:1241: Exception

During handling of the above exception, another exception occurred:

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7f1d66973e30>

    def test_get_user_team_slugs_general_exception(self):
        """Test team membership check with general exception."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_github = Mock()
            mock_github.get_organization.side_effect = Exception("Network error")
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           result = client.get_user_team_slugs(123456, "acme", "alice", ["release-team"])
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_github_client.py:1195: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.github_client.GitHubAppClient object at 0x7f1d623c4830>
installation_id = 123456, org_name = 'acme', username = 'alice'
allowed_teams = ['release-team']

    def get_user_team_slugs(
        self,
        installation_id: int,
        org_name: str,
        username: str,
        allowed_teams: list[str],
    ) -> list[str]:
        """Get team slugs the user is a member of from the allowed teams list.
    
        Args:
            installation_id: GitHub App installation ID
            org_name: Organization name
            username: GitHub username to check
            allowed_teams: List of team slugs to check (can be "org/team" or just "team")
    
        Returns:
            List of team slugs the user is a member of
        """
        start_time = time.time()
    
        with create_span(
            "github.get_user_team_slugs",
            {
                "github.org": org_name,
                "github.username": username,
                "github.installation_id": installation_id,
                "github.teams_to_check": len(allowed_teams),
            },
        ) as span:
            member_teams: list[str] = []
    
            try:
                client = self._get_installation_client(installation_id)
                org = client.get_organization(org_name)
    
                for team_ref in allowed_teams:
                    # Extract team slug (handle both "org/team" and "team" formats)
                    team_slug = team_ref.split("/")[-1] if "/" in team_ref else team_ref
    
                    try:
                        team = org.get_team_by_slug(team_slug)
                        # Check if user is a member
                        user = client.get_user(username)
                        if team.has_in_members(user):  # type: ignore[arg-type]
                            member_teams.append(team_slug)
                            logger.debug(
                                "User %s is a member of team %s",
                                username,
                                team_slug,
                                extra={
                                    "org": org_name,
                                    "username": username,
                                    "team": team_slug,
                                },
                            )
                    except GithubException as e:
                        # Team not found or no access - skip silently
                        logger.debug(
                            "Could not check team %s membership: %s",
                            team_slug,
                            e.data.get("message", str(e)) if hasattr(e, "data") else str(e),
                            extra={
                                "org": org_name,
                                "team": team_slug,
                                "username": username,
                            },
                        )
                        continue
    
                duration = time.time() - start_time
                github_api_request_duration_seconds.labels(operation="get_user_teams").observe(
                    duration
                )
                github_api_requests_total.labels(operation="get_user_teams", status="success").inc()
    
                self._update_rate_limit_metrics(client, installation_id)
    
                add_span_attributes(
                    span,
                    {
                        "github.member_teams": len(member_teams),
                        "github.teams_checked": len(allowed_teams),
                    },
                )
                set_span_ok(span)
    
                return member_teams
    
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/github_client.py:1093: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_general_exception - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 73 passed, 3 deselected, 1 warning in 2.30s
operator: core/NumberReplacer, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -22,7 +22,7 @@
 from stampbot.telemetry import add_span_attributes, create_span, set_span_error, set_span_ok
 
 # GitHub API configuration
-GITHUB_API_TIMEOUT = 30  # seconds
+GITHUB_API_TIMEOUT = 31  # seconds
 GITHUB_API_RETRY_TOTAL = 3
 GITHUB_API_RETRY_BACKOFF = 0.5  # exponential backoff factor
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/NumberReplacer, occurrence: 1, definition_name: None
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -22,7 +22,7 @@
 from stampbot.telemetry import add_span_attributes, create_span, set_span_error, set_span_ok
 
 # GitHub API configuration
-GITHUB_API_TIMEOUT = 30  # seconds
+GITHUB_API_TIMEOUT = 29  # seconds
 GITHUB_API_RETRY_TOTAL = 3
 GITHUB_API_RETRY_BACKOFF = 0.5  # exponential backoff factor
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/NumberReplacer, occurrence: 2, definition_name: None
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -23,7 +23,7 @@
 
 # GitHub API configuration
 GITHUB_API_TIMEOUT = 30  # seconds
-GITHUB_API_RETRY_TOTAL = 3
+GITHUB_API_RETRY_TOTAL = 4
 GITHUB_API_RETRY_BACKOFF = 0.5  # exponential backoff factor
 
 logger = get_logger(__name__)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/NumberReplacer, occurrence: 3, definition_name: None
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -23,7 +23,7 @@
 
 # GitHub API configuration
 GITHUB_API_TIMEOUT = 30  # seconds
-GITHUB_API_RETRY_TOTAL = 3
+GITHUB_API_RETRY_TOTAL = 2
 GITHUB_API_RETRY_BACKOFF = 0.5  # exponential backoff factor
 
 logger = get_logger(__name__)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/NumberReplacer, occurrence: 4, definition_name: None
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -24,7 +24,7 @@
 # GitHub API configuration
 GITHUB_API_TIMEOUT = 30  # seconds
 GITHUB_API_RETRY_TOTAL = 3
-GITHUB_API_RETRY_BACKOFF = 0.5  # exponential backoff factor
+GITHUB_API_RETRY_BACKOFF = 1.5  # exponential backoff factor
 
 logger = get_logger(__name__)
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/NumberReplacer, occurrence: 5, definition_name: None
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -24,7 +24,7 @@
 # GitHub API configuration
 GITHUB_API_TIMEOUT = 30  # seconds
 GITHUB_API_RETRY_TOTAL = 3
-GITHUB_API_RETRY_BACKOFF = 0.5  # exponential backoff factor
+GITHUB_API_RETRY_BACKOFF = -0.5  # exponential backoff factor
 
 logger = get_logger(__name__)
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/NumberReplacer, occurrence: 6, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -167,7 +167,7 @@
                 retry = Retry(
                     total=GITHUB_API_RETRY_TOTAL,
                     backoff_factor=GITHUB_API_RETRY_BACKOFF,
-                    status_forcelist=[500, 502, 503, 504],
+                    status_forcelist=[ 501, 502, 503, 504],
                     allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                 )
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/NumberReplacer, occurrence: 7, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -167,7 +167,7 @@
                 retry = Retry(
                     total=GITHUB_API_RETRY_TOTAL,
                     backoff_factor=GITHUB_API_RETRY_BACKOFF,
-                    status_forcelist=[500, 502, 503, 504],
+                    status_forcelist=[ 499, 502, 503, 504],
                     allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                 )
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/NumberReplacer, occurrence: 8, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -167,7 +167,7 @@
                 retry = Retry(
                     total=GITHUB_API_RETRY_TOTAL,
                     backoff_factor=GITHUB_API_RETRY_BACKOFF,
-                    status_forcelist=[500, 502, 503, 504],
+                    status_forcelist=[500, 503, 503, 504],
                     allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                 )
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/NumberReplacer, occurrence: 9, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -167,7 +167,7 @@
                 retry = Retry(
                     total=GITHUB_API_RETRY_TOTAL,
                     backoff_factor=GITHUB_API_RETRY_BACKOFF,
-                    status_forcelist=[500, 502, 503, 504],
+                    status_forcelist=[500, 501, 503, 504],
                     allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                 )
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/NumberReplacer, occurrence: 10, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -167,7 +167,7 @@
                 retry = Retry(
                     total=GITHUB_API_RETRY_TOTAL,
                     backoff_factor=GITHUB_API_RETRY_BACKOFF,
-                    status_forcelist=[500, 502, 503, 504],
+                    status_forcelist=[500, 502, 504, 504],
                     allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                 )
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/NumberReplacer, occurrence: 11, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -167,7 +167,7 @@
                 retry = Retry(
                     total=GITHUB_API_RETRY_TOTAL,
                     backoff_factor=GITHUB_API_RETRY_BACKOFF,
-                    status_forcelist=[500, 502, 503, 504],
+                    status_forcelist=[500, 502, 502, 504],
                     allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                 )
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.21s
operator: core/NumberReplacer, occurrence: 12, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -167,7 +167,7 @@
                 retry = Retry(
                     total=GITHUB_API_RETRY_TOTAL,
                     backoff_factor=GITHUB_API_RETRY_BACKOFF,
-                    status_forcelist=[500, 502, 503, 504],
+                    status_forcelist=[500, 502, 503, 505],
                     allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                 )
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.28s
operator: core/NumberReplacer, occurrence: 13, definition_name: _get_installation_client
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -167,7 +167,7 @@
                 retry = Retry(
                     total=GITHUB_API_RETRY_TOTAL,
                     backoff_factor=GITHUB_API_RETRY_BACKOFF,
-                    status_forcelist=[500, 502, 503, 504],
+                    status_forcelist=[500, 502, 503, 503],
                     allowed_methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
                 )
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/NumberReplacer, occurrence: 14, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -876,7 +876,7 @@
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
-                if e.status == 404:
+                if e.status == 405:
                     add_span_attributes(span, {"github.label_found": False})
                     set_span_ok(span)
                     return False
........................................................................ [ 30%]
...F
=================================== FAILURES ===================================
________________ TestRepoHasLabel.test_repo_has_label_not_found ________________

self = <tests.test_github_client.TestRepoHasLabel object at 0x7f0fc2db9d10>

    def test_repo_has_label_not_found(self):
        """Test repo_has_label returns False when label is missing."""
        from github.GithubException import GithubException
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = GithubException(404, {"message": "Not Found"}, None)
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.repo_has_label(123456, "owner/repo", "missing")
    
>           assert result is False
E           assert None is False

tests/test_github_client.py:1277: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:32:09 [debug    ] Could not verify label missing in owner/repo: 404 {"message": "Not Found"} extra={'repo': 'owner/repo', 'label': 'missing', 'installation_id': 123456, 'error': '404 {"message": "Not Found"}'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_not_found - assert None is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 75 passed, 3 deselected, 1 warning in 2.15s
operator: core/NumberReplacer, occurrence: 15, definition_name: repo_has_label
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -876,7 +876,7 @@
                 github_api_request_duration_seconds.labels(operation="get_label").observe(duration)
                 github_api_requests_total.labels(operation="get_label", status="failure").inc()
 
-                if e.status == 404:
+                if e.status == 403:
                     add_span_attributes(span, {"github.label_found": False})
                     set_span_ok(span)
                     return False
........................................................................ [ 30%]
...F
=================================== FAILURES ===================================
________________ TestRepoHasLabel.test_repo_has_label_not_found ________________

self = <tests.test_github_client.TestRepoHasLabel object at 0x7fd4c34ddd10>

    def test_repo_has_label_not_found(self):
        """Test repo_has_label returns False when label is missing."""
        from github.GithubException import GithubException
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_repo = Mock()
            mock_repo.get_label.side_effect = GithubException(404, {"message": "Not Found"}, None)
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.repo_has_label(123456, "owner/repo", "missing")
    
>           assert result is False
E           assert None is False

tests/test_github_client.py:1277: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:10:25 [debug    ] Could not verify label missing in owner/repo: 404 {"message": "Not Found"} extra={'repo': 'owner/repo', 'label': 'missing', 'installation_id': 123456, 'error': '404 {"message": "Not Found"}'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestRepoHasLabel::test_repo_has_label_not_found - assert None is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 75 passed, 3 deselected, 1 warning in 2.17s
operator: core/NumberReplacer, occurrence: 16, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -955,7 +955,7 @@
                     permission_index = permission_order.index(permission)
                     required_index = permission_order.index(required_permission)
                 except ValueError:
-                    permission_index = -1
+                    permission_index = - 2
                     required_index = 99
 
                 has_permission = permission_index >= required_index
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/NumberReplacer, occurrence: 17, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -955,7 +955,7 @@
                     permission_index = permission_order.index(permission)
                     required_index = permission_order.index(required_permission)
                 except ValueError:
-                    permission_index = -1
+                    permission_index = - 0
                     required_index = 99
 
                 has_permission = permission_index >= required_index
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/NumberReplacer, occurrence: 18, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -956,7 +956,7 @@
                     required_index = permission_order.index(required_permission)
                 except ValueError:
                     permission_index = -1
-                    required_index = 99
+                    required_index = 100
 
                 has_permission = permission_index >= required_index
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/NumberReplacer, occurrence: 19, definition_name: user_has_permission
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -956,7 +956,7 @@
                     required_index = permission_order.index(required_permission)
                 except ValueError:
                     permission_index = -1
-                    required_index = 99
+                    required_index = 98
 
                 has_permission = permission_index >= required_index
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/NumberReplacer, occurrence: 20, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1039,7 +1039,7 @@
 
                 for team_ref in allowed_teams:
                     # Extract team slug (handle both "org/team" and "team" formats)
-                    team_slug = team_ref.split("/")[-1] if "/" in team_ref else team_ref
+                    team_slug = team_ref.split("/")[- 2] if "/" in team_ref else team_ref
 
                     try:
                         team = org.get_team_by_slug(team_slug)
......................................................................F
=================================== FAILURES ===================================
________ TestGetUserTeamSlugs.test_get_user_team_slugs_with_org_prefix _________

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7fb7fdb55a90>

    def test_get_user_team_slugs_with_org_prefix(self):
        """Test team membership check with org/team format."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_user = Mock()
            mock_team = Mock()
            mock_team.has_in_members.return_value = True
            mock_org = Mock()
            mock_org.get_team_by_slug.return_value = mock_team
    
            mock_github = Mock()
            mock_github.get_organization.return_value = mock_org
            mock_github.get_user.return_value = mock_user
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_user_team_slugs(123456, "acme", "alice", ["acme/release-team"])
    
            # Should extract "release-team" from "acme/release-team"
>           mock_org.get_team_by_slug.assert_called_with("release-team")

tests/test_github_client.py:1077: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_organization().get_team_by_slug' id='140428139673120'>
args = ('release-team',), kwargs = {}, expected = call('release-team')
actual = call('acme')
_error_message = <function NonCallableMock.assert_called_with.<locals>._error_message at 0x7fb7f9630880>
cause = None

    def assert_called_with(self, /, *args, **kwargs):
        """assert that the last call was made with the specified arguments.
    
        Raises an AssertionError if the args and keyword args passed in are
        different to the last call to the mock."""
        if self.call_args is None:
            expected = self._format_mock_call_signature(args, kwargs)
            actual = 'not called.'
            error_message = ('expected call not found.\nExpected: %s\n  Actual: %s'
                    % (expected, actual))
            raise AssertionError(error_message)
    
        def _error_message():
            msg = self._format_mock_failure_message(args, kwargs)
            return msg
        expected = self._call_matcher(_Call((args, kwargs), two=True))
        actual = self._call_matcher(self.call_args)
        if actual != expected:
            cause = expected if isinstance(expected, Exception) else None
>           raise AssertionError(_error_message()) from cause
E           AssertionError: expected call not found.
E           Expected: get_team_by_slug('release-team')
E             Actual: get_team_by_slug('acme')

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:986: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 05:43:40 [debug    ] User alice is a member of team acme extra={'org': 'acme', 'username': 'alice', 'team': 'acme'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_with_org_prefix - AssertionError: expected call not found.
Expected: get_team_by_slug('release-team')
  Actual: get_team_by_slug('acme')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 70 passed, 3 deselected, 1 warning in 2.20s
operator: core/NumberReplacer, occurrence: 21, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1039,7 +1039,7 @@
 
                 for team_ref in allowed_teams:
                     # Extract team slug (handle both "org/team" and "team" formats)
-                    team_slug = team_ref.split("/")[-1] if "/" in team_ref else team_ref
+                    team_slug = team_ref.split("/")[- 0] if "/" in team_ref else team_ref
 
                     try:
                         team = org.get_team_by_slug(team_slug)
......................................................................F
=================================== FAILURES ===================================
________ TestGetUserTeamSlugs.test_get_user_team_slugs_with_org_prefix _________

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7fcf1a091a90>

    def test_get_user_team_slugs_with_org_prefix(self):
        """Test team membership check with org/team format."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            mock_user = Mock()
            mock_team = Mock()
            mock_team.has_in_members.return_value = True
            mock_org = Mock()
            mock_org.get_team_by_slug.return_value = mock_team
    
            mock_github = Mock()
            mock_github.get_organization.return_value = mock_org
            mock_github.get_user.return_value = mock_user
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_user_team_slugs(123456, "acme", "alice", ["acme/release-team"])
    
            # Should extract "release-team" from "acme/release-team"
>           mock_org.get_team_by_slug.assert_called_with("release-team")

tests/test_github_client.py:1077: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Mock name='Github().get_organization().get_team_by_slug' id='140527401301536'>
args = ('release-team',), kwargs = {}, expected = call('release-team')
actual = call('acme')
_error_message = <function NonCallableMock.assert_called_with.<locals>._error_message at 0x7fcf15d58880>
cause = None

    def assert_called_with(self, /, *args, **kwargs):
        """assert that the last call was made with the specified arguments.
    
        Raises an AssertionError if the args and keyword args passed in are
        different to the last call to the mock."""
        if self.call_args is None:
            expected = self._format_mock_call_signature(args, kwargs)
            actual = 'not called.'
            error_message = ('expected call not found.\nExpected: %s\n  Actual: %s'
                    % (expected, actual))
            raise AssertionError(error_message)
    
        def _error_message():
            msg = self._format_mock_failure_message(args, kwargs)
            return msg
        expected = self._call_matcher(_Call((args, kwargs), two=True))
        actual = self._call_matcher(self.call_args)
        if actual != expected:
            cause = expected if isinstance(expected, Exception) else None
>           raise AssertionError(_error_message()) from cause
E           AssertionError: expected call not found.
E           Expected: get_team_by_slug('release-team')
E             Actual: get_team_by_slug('acme')

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:986: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29 04:26:14 [debug    ] User alice is a member of team acme extra={'org': 'acme', 'username': 'alice', 'team': 'acme'}
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_with_org_prefix - AssertionError: expected call not found.
Expected: get_team_by_slug('release-team')
  Actual: get_team_by_slug('acme')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 70 passed, 3 deselected, 1 warning in 2.19s
operator: core/RemoveDecorator, occurrence: 0, definition_name: GitHubAppClient
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -83,8 +83,6 @@
         self._auth = Auth.AppAuth(app_id, private_key)
         self._integration = GithubIntegration(auth=self._auth)
         self._initialized = True
-
-    @property
     def integration(self) -> GithubIntegration:
         """Get GitHub integration, initializing if needed.
 
.........................................F
=================================== FAILURES ===================================
_____ TestIntegrationProperty.test_integration_raises_when_not_initialized _____

self = <tests.test_github_client.TestIntegrationProperty object at 0x7f2957b8f890>

    def test_integration_raises_when_not_initialized(self):
        """Test that integration property raises when not initialized after _ensure_initialized."""
        with patch("stampbot.github_client.is_configured", return_value=False):
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
>           with pytest.raises(RuntimeError):
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           Failed: DID NOT RAISE <class 'RuntimeError'>

tests/test_github_client.py:94: Failed
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestIntegrationProperty::test_integration_raises_when_not_initialized - Failed: DID NOT RAISE <class 'RuntimeError'>
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 41 passed, 3 deselected, 1 warning in 2.10s
operator: core/ZeroIterationForLoop, occurrence: 0, definition_name: find_bot_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -542,7 +542,7 @@
 
                 # Find all reviews by bot that are approvals
                 bot_review_ids = []
-                for review in pr.get_reviews():
+                for review in []:
                     if review.user.login == bot_user and review.state == "APPROVED":
                         bot_review_ids.append(review.id)
 
.............................................................F
=================================== FAILURES ===================================
_______________ TestFindBotReviews.test_find_bot_reviews_success _______________

self = <tests.test_github_client.TestFindBotReviews object at 0x7fd0ea8a91d0>

    def test_find_bot_reviews_success(self):
        """Test successful bot review finding."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            # Create mock reviews
            bot_review = Mock()
            bot_review.user.login = "stampbot[bot]"
            bot_review.state = "APPROVED"
            bot_review.id = 123
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [bot_review, other_review]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_reviews(123456, "owner/repo", 42)
    
>           assert result == [123]
E           assert [] == [123]
E             
E             Right contains one more item: 123
E             
E             Full diff:
E             + []
E             - [
E             -     123,
E             - ]

tests/test_github_client.py:685: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotReviews::test_find_bot_reviews_success - assert [] == [123]
  
  Right contains one more item: 123
  
  Full diff:
  + []
  - [
  -     123,
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 61 passed, 3 deselected, 1 warning in 2.12s
operator: core/ZeroIterationForLoop, occurrence: 1, definition_name: find_bot_approval_reviews
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -621,7 +621,7 @@
                 bot_user = f"{app_info.slug}[bot]"
 
                 bot_reviews: list[BotReview] = []
-                for review in pr.get_reviews():
+                for review in []:
                     if review.user.login == bot_user and review.state in (
                         "APPROVED",
                         "DISMISSED",
...............................................................F
=================================== FAILURES ===================================
______ TestFindBotApprovalReviews.test_find_bot_approval_reviews_success _______

self = <tests.test_github_client.TestFindBotApprovalReviews object at 0x7f59fb595450>

    def test_find_bot_approval_reviews_success(self):
        """Test successful bot approval review state lookup."""
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration.get_app.return_value = Mock(slug="stampbot")
            mock_integration_cls.return_value = mock_integration
    
            bot_approved_review = Mock()
            bot_approved_review.user.login = "stampbot[bot]"
            bot_approved_review.state = "APPROVED"
            bot_approved_review.id = 123
            bot_approved_review.commit_id = "headsha"
    
            bot_dismissed_review = Mock()
            bot_dismissed_review.user.login = "stampbot[bot]"
            bot_dismissed_review.state = "DISMISSED"
            bot_dismissed_review.id = 124
            bot_dismissed_review.commit_id = "oldsha"
    
            bot_commented_review = Mock()
            bot_commented_review.user.login = "stampbot[bot]"
            bot_commented_review.state = "COMMENTED"
            bot_commented_review.id = 125
    
            other_review = Mock()
            other_review.user.login = "other-user"
            other_review.state = "APPROVED"
            other_review.id = 456
    
            mock_pr = Mock()
            mock_pr.get_reviews.return_value = [
                bot_approved_review,
                bot_dismissed_review,
                bot_commented_review,
                other_review,
            ]
            mock_repo = Mock()
            mock_repo.get_pull.return_value = mock_pr
            mock_github = Mock()
            mock_github.get_repo.return_value = mock_repo
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.find_bot_approval_reviews(123456, "owner/repo", 42)
    
>           assert result == [
                {"id": 123, "state": "APPROVED", "commit_id": "headsha"},
                {"id": 124, "state": "DISMISSED", "commit_id": "oldsha"},
            ]
E           AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
E             
E             Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
E             
E             Full diff:
E             + []
E             - [
E             -     {
E             -         'commit_id': 'headsha',
E             -         'id': 123,
E             -         'state': 'APPROVED',
E             -     },
E             -     {
E             -         'commit_id': 'oldsha',
E             -         'id': 124,
E             -         'state': 'DISMISSED',
E             -     },
E             - ]

tests/test_github_client.py:790: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestFindBotApprovalReviews::test_find_bot_approval_reviews_success - AssertionError: assert [] == [{'commit_id'... 'DISMISSED'}]
  
  Right contains 2 more items, first extra item: {'commit_id': 'headsha', 'id': 123, 'state': 'APPROVED'}
  
  Full diff:
  + []
  - [
  -     {
  -         'commit_id': 'headsha',
  -         'id': 123,
  -         'state': 'APPROVED',
  -     },
  -     {
  -         'commit_id': 'oldsha',
  -         'id': 124,
  -         'state': 'DISMISSED',
  -     },
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 63 passed, 3 deselected, 1 warning in 2.13s
operator: core/ZeroIterationForLoop, occurrence: 2, definition_name: get_user_team_slugs
--- mutation diff ---
--- astampbot/github_client.py
+++ bstampbot/github_client.py
@@ -1037,7 +1037,7 @@
                 client = self._get_installation_client(installation_id)
                 org = client.get_organization(org_name)
 
-                for team_ref in allowed_teams:
+                for team_ref in []:
                     # Extract team slug (handle both "org/team" and "team" formats)
                     team_slug = team_ref.split("/")[-1] if "/" in team_ref else team_ref
 
.....................................................................F
=================================== FAILURES ===================================
____________ TestGetUserTeamSlugs.test_get_user_team_slugs_success _____________

self = <tests.test_github_client.TestGetUserTeamSlugs object at 0x7f232b9fd950>

    def test_get_user_team_slugs_success(self):
        """Test successful team membership check."""
    
        with (
            patch("stampbot.github_client.is_configured", return_value=True),
            patch("stampbot.github_client.settings") as mock_settings,
            patch("stampbot.github_client.Auth.AppAuth"),
            patch("stampbot.github_client.GithubIntegration") as mock_integration_cls,
            patch("stampbot.github_client.Github") as mock_github_cls,
            patch("stampbot.github_client.create_span") as mock_span,
        ):
            mock_settings.app_id = 12345
            mock_settings.private_key = TEST_PEM_KEY
            mock_settings.otel_enabled = False
    
            mock_integration = Mock()
            mock_token = Mock()
            mock_token.token = TEST_TOKEN
            mock_integration.get_access_token.return_value = mock_token
            mock_integration_cls.return_value = mock_integration
    
            # Mock user
            mock_user = Mock()
            mock_user.login = "alice"
    
            # Mock team that has alice as member
            mock_team = Mock()
            mock_team.has_in_members.return_value = True
    
            # Mock org
            mock_org = Mock()
            mock_org.get_team_by_slug.return_value = mock_team
    
            mock_github = Mock()
            mock_github.get_organization.return_value = mock_org
            mock_github.get_user.return_value = mock_user
            mock_github.get_rate_limit.return_value = Mock(core=Mock(remaining=4500, limit=5000))
            mock_github_cls.return_value = mock_github
    
            mock_span.return_value.__enter__ = Mock(return_value=None)
            mock_span.return_value.__exit__ = Mock(return_value=False)
    
            from stampbot.github_client import GitHubAppClient
    
            client = GitHubAppClient()
            result = client.get_user_team_slugs(
                123456, "acme", "alice", ["release-team", "deploy-team"]
            )
    
>           assert result == ["release-team", "deploy-team"]
E           AssertionError: assert [] == ['release-tea...'deploy-team']
E             
E             Right contains 2 more items, first extra item: 'release-team'
E             
E             Full diff:
E             + []
E             - [
E             -     'release-team',
E             -     'deploy-team',
E             - ]

tests/test_github_client.py:1033: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_github_client.py::TestGetUserTeamSlugs::test_get_user_team_slugs_success - AssertionError: assert [] == ['release-tea...'deploy-team']
  
  Right contains 2 more items, first extra item: 'release-team'
  
  Full diff:
  + []
  - [
  -     'release-team',
  -     'deploy-team',
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 69 passed, 3 deselected, 1 warning in 2.15s
operator: core/ReplaceBinaryOperator_Add_Sub, occurrence: 0, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' - APP_VERSION + '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7f0a621239d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' - APP_VERSION + '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for -: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for -: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.66s
operator: core/ReplaceBinaryOperator_Add_Sub, occurrence: 1, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' + APP_VERSION - '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7fb5392bf9d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' + APP_VERSION - '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for -: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for -: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.70s
operator: core/ReplaceBinaryOperator_Add_Mul, occurrence: 0, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' * APP_VERSION + '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7f88a94339d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' * APP_VERSION + '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: can't multiply sequence by non-int of type 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: can't multiply sequence by non-int of type 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.63s
operator: core/ReplaceBinaryOperator_Add_Mul, occurrence: 1, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' + APP_VERSION * '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7fdaa41379d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' + APP_VERSION * '", "status": "running"}',
                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: can't multiply sequence by non-int of type 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: can't multiply sequence by non-int of type 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.65s
operator: core/ReplaceBinaryOperator_Add_Div, occurrence: 0, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' / APP_VERSION + '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7fecd85239d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' / APP_VERSION + '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for /: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for /: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.64s
operator: core/ReplaceBinaryOperator_Add_Div, occurrence: 1, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' + APP_VERSION / '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7fcd85ccb9d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' + APP_VERSION / '", "status": "running"}',
                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for /: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for /: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.65s
operator: core/ReplaceBinaryOperator_Add_FloorDiv, occurrence: 0, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' // APP_VERSION + '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7fe9d3bc39d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' // APP_VERSION + '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for //: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for //: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceBinaryOperator_Add_FloorDiv, occurrence: 1, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' + APP_VERSION // '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7f70de1bf9d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' + APP_VERSION // '", "status": "running"}',
                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for //: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for //: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceBinaryOperator_Add_Mod, occurrence: 0, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' % APP_VERSION + '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7f641df339d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' % APP_VERSION + '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: not all arguments converted during string formatting

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: not all arguments converted during string formatting
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.66s
operator: core/ReplaceBinaryOperator_Add_Mod, occurrence: 1, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' + APP_VERSION % '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7ff07721f9d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' + APP_VERSION % '", "status": "running"}',
                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: not all arguments converted during string formatting

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: not all arguments converted during string formatting
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.65s
operator: core/ReplaceBinaryOperator_Add_Pow, occurrence: 0, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' ** APP_VERSION + '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7f7a43f379d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' ** APP_VERSION + '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceBinaryOperator_Add_Pow, occurrence: 1, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' + APP_VERSION ** '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7f061f0339d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' + APP_VERSION ** '", "status": "running"}',
                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.65s
operator: core/ReplaceBinaryOperator_Add_RShift, occurrence: 0, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' >> APP_VERSION + '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7fb31ea279d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' >> APP_VERSION + '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for >>: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for >>: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.65s
operator: core/ReplaceBinaryOperator_Add_RShift, occurrence: 1, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' + APP_VERSION >> '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7fa8aac239d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' + APP_VERSION >> '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for >>: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for >>: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.64s
operator: core/ReplaceBinaryOperator_Add_LShift, occurrence: 0, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' << APP_VERSION + '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7f927dac39d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' << APP_VERSION + '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for <<: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for <<: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceBinaryOperator_Add_LShift, occurrence: 1, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' + APP_VERSION << '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7fa0304379d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' + APP_VERSION << '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for <<: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for <<: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceBinaryOperator_Add_BitOr, occurrence: 0, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' | APP_VERSION + '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7f171a6339d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' | APP_VERSION + '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for |: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for |: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.65s
operator: core/ReplaceBinaryOperator_Add_BitOr, occurrence: 1, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' + APP_VERSION | '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7fd1d7f339d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' + APP_VERSION | '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for |: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for |: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.66s
operator: core/ReplaceBinaryOperator_Add_BitAnd, occurrence: 0, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' & APP_VERSION + '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7f84a8f3b9d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' & APP_VERSION + '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for &: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for &: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.67s
operator: core/ReplaceBinaryOperator_Add_BitAnd, occurrence: 1, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' + APP_VERSION & '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7f2c778239d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' + APP_VERSION & '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for &: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for &: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.66s
operator: core/ReplaceBinaryOperator_Add_BitXor, occurrence: 0, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' ^ APP_VERSION + '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7ff0a671b9d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' ^ APP_VERSION + '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for ^: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for ^: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.66s
operator: core/ReplaceBinaryOperator_Add_BitXor, occurrence: 1, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -224,7 +224,7 @@
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
-        content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
+        content='{"app": "stampbot", "version": "' + APP_VERSION ^ '", "status": "running"}',
         media_type="application/json",
     )
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7faebcf239d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
>       response = test_client.get("/")
                   ^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @app.get("/")
    async def root() -> Response:
        """Root endpoint - redirects to setup if not configured.
    
        Returns:
            Redirect to /setup if unconfigured, otherwise JSON status response.
        """
        if not is_configured() and settings.setup_enabled:
            return RedirectResponse(url="/setup", status_code=307)
    
        return Response(
>           content='{"app": "stampbot", "version": "' + APP_VERSION ^ '", "status": "running"}',
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            media_type="application/json",
        )
E       TypeError: unsupported operand type(s) for ^: 'str' and 'str'

stampbot/main.py:227: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - TypeError: unsupported operand type(s) for ^: 'str' and 'str'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.65s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 0, definition_name: metrics_middleware
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -124,7 +124,7 @@
     try:
         response = await call_next(request)
 
-        duration = time.time() - start_time
+        duration = time.time() + start_time
 
         # Track request metrics
         http_requests_total.labels(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_Add, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -354,7 +354,7 @@
     try:
         start_time = time.time()
         result = await webhook_handler.handle_event(x_github_event, payload)
-        duration = time.time() - start_time
+        duration = time.time() + start_time
 
         webhook_processing_duration_seconds.labels(event_type=x_github_event or "unknown").observe(
             duration
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 0, definition_name: metrics_middleware
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -124,7 +124,7 @@
     try:
         response = await call_next(request)
 
-        duration = time.time() - start_time
+        duration = time.time() * start_time
 
         # Track request metrics
         http_requests_total.labels(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mul, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -354,7 +354,7 @@
     try:
         start_time = time.time()
         result = await webhook_handler.handle_event(x_github_event, payload)
-        duration = time.time() - start_time
+        duration = time.time() * start_time
 
         webhook_processing_duration_seconds.labels(event_type=x_github_event or "unknown").observe(
             duration
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.26s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 0, definition_name: metrics_middleware
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -124,7 +124,7 @@
     try:
         response = await call_next(request)
 
-        duration = time.time() - start_time
+        duration = time.time() / start_time
 
         # Track request metrics
         http_requests_total.labels(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceBinaryOperator_Sub_Div, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -354,7 +354,7 @@
     try:
         start_time = time.time()
         result = await webhook_handler.handle_event(x_github_event, payload)
-        duration = time.time() - start_time
+        duration = time.time() / start_time
 
         webhook_processing_duration_seconds.labels(event_type=x_github_event or "unknown").observe(
             duration
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.27s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 0, definition_name: metrics_middleware
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -124,7 +124,7 @@
     try:
         response = await call_next(request)
 
-        duration = time.time() - start_time
+        duration = time.time() // start_time
 
         # Track request metrics
         http_requests_total.labels(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Sub_FloorDiv, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -354,7 +354,7 @@
     try:
         start_time = time.time()
         result = await webhook_handler.handle_event(x_github_event, payload)
-        duration = time.time() - start_time
+        duration = time.time() // start_time
 
         webhook_processing_duration_seconds.labels(event_type=x_github_event or "unknown").observe(
             duration
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 0, definition_name: metrics_middleware
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -124,7 +124,7 @@
     try:
         response = await call_next(request)
 
-        duration = time.time() - start_time
+        duration = time.time() % start_time
 
         # Track request metrics
         http_requests_total.labels(
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Mod, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -354,7 +354,7 @@
     try:
         start_time = time.time()
         result = await webhook_handler.handle_event(x_github_event, payload)
-        duration = time.time() - start_time
+        duration = time.time() % start_time
 
         webhook_processing_duration_seconds.labels(event_type=x_github_event or "unknown").observe(
             duration
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 0, definition_name: metrics_middleware
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -124,7 +124,7 @@
     try:
         response = await call_next(request)
 
-        duration = time.time() - start_time
+        duration = time.time() ** start_time
 
         # Track request metrics
         http_requests_total.labels(
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
        from stampbot.main import app
    
        # Use TestClient as context manager to trigger lifespan events
        with TestClient(app) as client:
            # App should be running
>           response = client.get("/health")
                       ^^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:20: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

request = <starlette.middleware.base._CachedRequest object at 0x7fdcadc04440>
call_next = <function BaseHTTPMiddleware.__call__.<locals>.call_next at 0x7fdcada5f270>

    @app.middleware("http")
    async def metrics_middleware(request: Request, call_next: Any) -> Response:
        """Middleware to track HTTP metrics.
    
        Args:
            request: Incoming HTTP request.
            call_next: Next middleware or route handler.
    
        Returns:
            HTTP response from downstream handler.
        """
        method = request.method
        endpoint = request.url.path
    
        # Track in-progress requests
        http_requests_in_progress.labels(method=method, endpoint=endpoint).inc()
    
        start_time = time.time()
    
        try:
            response = await call_next(request)
    
>           duration = time.time() ** start_time
                       ^^^^^^^^^^^^^^^^^^^^^^^^^
E           OverflowError: (34, 'Numerical result out of range')

stampbot/main.py:127: OverflowError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:31:26.820709Z [info     ] OpenTelemetry disabled         [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info
2026-06-29T04:31:26.942678Z [info     ] Starting stampbot on 0.0.0.0:8000 [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info extra={'host': '0.0.0.0', 'port': 8000, 'log_level': 'INFO'}
2026-06-29T04:31:26.942986Z [info     ] GitHub App credentials configured successfully [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
2026-06-29T04:31:26.945262Z [info     ] Shutting down stampbot         [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - OverflowError: (34, 'Numerical result out of range')
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.52s
operator: core/ReplaceBinaryOperator_Sub_Pow, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -354,7 +354,7 @@
     try:
         start_time = time.time()
         result = await webhook_handler.handle_event(x_github_event, payload)
-        duration = time.time() - start_time
+        duration = time.time() ** start_time
 
         webhook_processing_duration_seconds.labels(event_type=x_github_event or "unknown").observe(
             duration
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7fb3eda82cf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
>       assert response.status_code == 200
E       assert 500 == 200
E        +  where 500 = <Response [500 Internal Server Error]>.status_code

tests/test_main.py:217: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:49:20.570804Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T05:49:20.571006Z [error    ] Error handling webhook event: (34, 'Numerical result out of range') [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=error client_ip=testclient extra={'error': "(34, 'Numerical result out of range')"}
2026-06-29T05:49:20.571794Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 500 Internal Server Error" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:49:20.570804Z'}
ERROR    stampbot.main:main.py:367 {'extra': {'error': "(34, 'Numerical result out of range')"}, 'event': "Error handling webhook event: (34, 'Numerical result out of range')", 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'error', 'timestamp': '2026-06-29T05:49:20.571006Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 500 Internal Server Error"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - assert 500 == 200
 +  where 500 = <Response [500 Internal Server Error]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.36s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 0, definition_name: metrics_middleware
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -124,7 +124,7 @@
     try:
         response = await call_next(request)
 
-        duration = time.time() - start_time
+        duration = time.time() >> start_time
 
         # Track request metrics
         http_requests_total.labels(
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
        from stampbot.main import app
    
        # Use TestClient as context manager to trigger lifespan events
        with TestClient(app) as client:
            # App should be running
>           response = client.get("/health")
                       ^^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:20: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

request = <starlette.middleware.base._CachedRequest object at 0x7fe225118440>
call_next = <function BaseHTTPMiddleware.__call__.<locals>.call_next at 0x7fe224f7b110>

    @app.middleware("http")
    async def metrics_middleware(request: Request, call_next: Any) -> Response:
        """Middleware to track HTTP metrics.
    
        Args:
            request: Incoming HTTP request.
            call_next: Next middleware or route handler.
    
        Returns:
            HTTP response from downstream handler.
        """
        method = request.method
        endpoint = request.url.path
    
        # Track in-progress requests
        http_requests_in_progress.labels(method=method, endpoint=endpoint).inc()
    
        start_time = time.time()
    
        try:
            response = await call_next(request)
    
>           duration = time.time() >> start_time
                       ^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for >>: 'float' and 'float'

stampbot/main.py:127: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:52:06.697456Z [info     ] OpenTelemetry disabled         [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info
2026-06-29T04:52:06.822543Z [info     ] Starting stampbot on 0.0.0.0:8000 [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info extra={'host': '0.0.0.0', 'port': 8000, 'log_level': 'INFO'}
2026-06-29T04:52:06.822890Z [info     ] GitHub App credentials configured successfully [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
2026-06-29T04:52:06.825433Z [info     ] Shutting down stampbot         [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - TypeError: unsupported operand type(s) for >>: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.54s
operator: core/ReplaceBinaryOperator_Sub_RShift, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -354,7 +354,7 @@
     try:
         start_time = time.time()
         result = await webhook_handler.handle_event(x_github_event, payload)
-        duration = time.time() - start_time
+        duration = time.time() >> start_time
 
         webhook_processing_duration_seconds.labels(event_type=x_github_event or "unknown").observe(
             duration
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7f5a0df82cf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
>       assert response.status_code == 200
E       assert 500 == 200
E        +  where 500 = <Response [500 Internal Server Error]>.status_code

tests/test_main.py:217: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:24:05.403012Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T04:24:05.403206Z [error    ] Error handling webhook event: unsupported operand type(s) for >>: 'float' and 'float' [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=error client_ip=testclient extra={'error': "unsupported operand type(s) for >>: 'float' and 'float'"}
2026-06-29T04:24:05.404002Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 500 Internal Server Error" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:24:05.403012Z'}
ERROR    stampbot.main:main.py:367 {'extra': {'error': "unsupported operand type(s) for >>: 'float' and 'float'"}, 'event': "Error handling webhook event: unsupported operand type(s) for >>: 'float' and 'float'", 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'error', 'timestamp': '2026-06-29T04:24:05.403206Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 500 Internal Server Error"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - assert 500 == 200
 +  where 500 = <Response [500 Internal Server Error]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.36s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 0, definition_name: metrics_middleware
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -124,7 +124,7 @@
     try:
         response = await call_next(request)
 
-        duration = time.time() - start_time
+        duration = time.time() << start_time
 
         # Track request metrics
         http_requests_total.labels(
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
        from stampbot.main import app
    
        # Use TestClient as context manager to trigger lifespan events
        with TestClient(app) as client:
            # App should be running
>           response = client.get("/health")
                       ^^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:20: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

request = <starlette.middleware.base._CachedRequest object at 0x7fd5a9124050>
call_next = <function BaseHTTPMiddleware.__call__.<locals>.call_next at 0x7fd5a8f87110>

    @app.middleware("http")
    async def metrics_middleware(request: Request, call_next: Any) -> Response:
        """Middleware to track HTTP metrics.
    
        Args:
            request: Incoming HTTP request.
            call_next: Next middleware or route handler.
    
        Returns:
            HTTP response from downstream handler.
        """
        method = request.method
        endpoint = request.url.path
    
        # Track in-progress requests
        http_requests_in_progress.labels(method=method, endpoint=endpoint).inc()
    
        start_time = time.time()
    
        try:
            response = await call_next(request)
    
>           duration = time.time() << start_time
                       ^^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for <<: 'float' and 'float'

stampbot/main.py:127: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:04:57.082731Z [info     ] OpenTelemetry disabled         [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info
2026-06-29T05:04:57.207104Z [info     ] Starting stampbot on 0.0.0.0:8000 [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info extra={'host': '0.0.0.0', 'port': 8000, 'log_level': 'INFO'}
2026-06-29T05:04:57.207436Z [info     ] GitHub App credentials configured successfully [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
2026-06-29T05:04:57.209678Z [info     ] Shutting down stampbot         [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - TypeError: unsupported operand type(s) for <<: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.58s
operator: core/ReplaceBinaryOperator_Sub_LShift, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -354,7 +354,7 @@
     try:
         start_time = time.time()
         result = await webhook_handler.handle_event(x_github_event, payload)
-        duration = time.time() - start_time
+        duration = time.time() << start_time
 
         webhook_processing_duration_seconds.labels(event_type=x_github_event or "unknown").observe(
             duration
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7fdcdab82cf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
>       assert response.status_code == 200
E       assert 500 == 200
E        +  where 500 = <Response [500 Internal Server Error]>.status_code

tests/test_main.py:217: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:28:03.997336Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T05:28:03.997534Z [error    ] Error handling webhook event: unsupported operand type(s) for <<: 'float' and 'float' [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=error client_ip=testclient extra={'error': "unsupported operand type(s) for <<: 'float' and 'float'"}
2026-06-29T05:28:03.998331Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 500 Internal Server Error" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:28:03.997336Z'}
ERROR    stampbot.main:main.py:367 {'extra': {'error': "unsupported operand type(s) for <<: 'float' and 'float'"}, 'event': "Error handling webhook event: unsupported operand type(s) for <<: 'float' and 'float'", 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'error', 'timestamp': '2026-06-29T05:28:03.997534Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 500 Internal Server Error"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - assert 500 == 200
 +  where 500 = <Response [500 Internal Server Error]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.49s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 0, definition_name: metrics_middleware
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -124,7 +124,7 @@
     try:
         response = await call_next(request)
 
-        duration = time.time() - start_time
+        duration = time.time() | start_time
 
         # Track request metrics
         http_requests_total.labels(
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
        from stampbot.main import app
    
        # Use TestClient as context manager to trigger lifespan events
        with TestClient(app) as client:
            # App should be running
>           response = client.get("/health")
                       ^^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:20: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

request = <starlette.middleware.base._CachedRequest object at 0x7ff8b0ef8050>
call_next = <function BaseHTTPMiddleware.__call__.<locals>.call_next at 0x7ff8b0b5f110>

    @app.middleware("http")
    async def metrics_middleware(request: Request, call_next: Any) -> Response:
        """Middleware to track HTTP metrics.
    
        Args:
            request: Incoming HTTP request.
            call_next: Next middleware or route handler.
    
        Returns:
            HTTP response from downstream handler.
        """
        method = request.method
        endpoint = request.url.path
    
        # Track in-progress requests
        http_requests_in_progress.labels(method=method, endpoint=endpoint).inc()
    
        start_time = time.time()
    
        try:
            response = await call_next(request)
    
>           duration = time.time() | start_time
                       ^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for |: 'float' and 'float'

stampbot/main.py:127: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:15:21.600012Z [info     ] OpenTelemetry disabled         [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info
2026-06-29T05:15:21.721862Z [info     ] Starting stampbot on 0.0.0.0:8000 [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info extra={'host': '0.0.0.0', 'port': 8000, 'log_level': 'INFO'}
2026-06-29T05:15:21.722168Z [info     ] GitHub App credentials configured successfully [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
2026-06-29T05:15:21.724434Z [info     ] Shutting down stampbot         [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - TypeError: unsupported operand type(s) for |: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.52s
operator: core/ReplaceBinaryOperator_Sub_BitOr, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -354,7 +354,7 @@
     try:
         start_time = time.time()
         result = await webhook_handler.handle_event(x_github_event, payload)
-        duration = time.time() - start_time
+        duration = time.time() | start_time
 
         webhook_processing_duration_seconds.labels(event_type=x_github_event or "unknown").observe(
             duration
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7f0be358acf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
>       assert response.status_code == 200
E       assert 500 == 200
E        +  where 500 = <Response [500 Internal Server Error]>.status_code

tests/test_main.py:217: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:41:50.454717Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T04:41:50.454916Z [error    ] Error handling webhook event: unsupported operand type(s) for |: 'float' and 'float' [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=error client_ip=testclient extra={'error': "unsupported operand type(s) for |: 'float' and 'float'"}
2026-06-29T04:41:50.455702Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 500 Internal Server Error" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:41:50.454717Z'}
ERROR    stampbot.main:main.py:367 {'extra': {'error': "unsupported operand type(s) for |: 'float' and 'float'"}, 'event': "Error handling webhook event: unsupported operand type(s) for |: 'float' and 'float'", 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'error', 'timestamp': '2026-06-29T04:41:50.454916Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 500 Internal Server Error"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - assert 500 == 200
 +  where 500 = <Response [500 Internal Server Error]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.36s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 0, definition_name: metrics_middleware
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -124,7 +124,7 @@
     try:
         response = await call_next(request)
 
-        duration = time.time() - start_time
+        duration = time.time() & start_time
 
         # Track request metrics
         http_requests_total.labels(
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
        from stampbot.main import app
    
        # Use TestClient as context manager to trigger lifespan events
        with TestClient(app) as client:
            # App should be running
>           response = client.get("/health")
                       ^^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:20: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

request = <starlette.middleware.base._CachedRequest object at 0x7f93b5918440>
call_next = <function BaseHTTPMiddleware.__call__.<locals>.call_next at 0x7f93b577b110>

    @app.middleware("http")
    async def metrics_middleware(request: Request, call_next: Any) -> Response:
        """Middleware to track HTTP metrics.
    
        Args:
            request: Incoming HTTP request.
            call_next: Next middleware or route handler.
    
        Returns:
            HTTP response from downstream handler.
        """
        method = request.method
        endpoint = request.url.path
    
        # Track in-progress requests
        http_requests_in_progress.labels(method=method, endpoint=endpoint).inc()
    
        start_time = time.time()
    
        try:
            response = await call_next(request)
    
>           duration = time.time() & start_time
                       ^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for &: 'float' and 'float'

stampbot/main.py:127: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:36:39.358130Z [info     ] OpenTelemetry disabled         [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info
2026-06-29T05:36:39.480150Z [info     ] Starting stampbot on 0.0.0.0:8000 [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info extra={'host': '0.0.0.0', 'port': 8000, 'log_level': 'INFO'}
2026-06-29T05:36:39.480482Z [info     ] GitHub App credentials configured successfully [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
2026-06-29T05:36:39.482743Z [info     ] Shutting down stampbot         [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - TypeError: unsupported operand type(s) for &: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.53s
operator: core/ReplaceBinaryOperator_Sub_BitAnd, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -354,7 +354,7 @@
     try:
         start_time = time.time()
         result = await webhook_handler.handle_event(x_github_event, payload)
-        duration = time.time() - start_time
+        duration = time.time() & start_time
 
         webhook_processing_duration_seconds.labels(event_type=x_github_event or "unknown").observe(
             duration
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7f4d5c88ecf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
>       assert response.status_code == 200
E       assert 500 == 200
E        +  where 500 = <Response [500 Internal Server Error]>.status_code

tests/test_main.py:217: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:36:29.981033Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T05:36:29.981221Z [error    ] Error handling webhook event: unsupported operand type(s) for &: 'float' and 'float' [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=error client_ip=testclient extra={'error': "unsupported operand type(s) for &: 'float' and 'float'"}
2026-06-29T05:36:29.982070Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 500 Internal Server Error" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:36:29.981033Z'}
ERROR    stampbot.main:main.py:367 {'extra': {'error': "unsupported operand type(s) for &: 'float' and 'float'"}, 'event': "Error handling webhook event: unsupported operand type(s) for &: 'float' and 'float'", 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'error', 'timestamp': '2026-06-29T05:36:29.981221Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 500 Internal Server Error"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - assert 500 == 200
 +  where 500 = <Response [500 Internal Server Error]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.38s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 0, definition_name: metrics_middleware
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -124,7 +124,7 @@
     try:
         response = await call_next(request)
 
-        duration = time.time() - start_time
+        duration = time.time() ^ start_time
 
         # Track request metrics
         http_requests_total.labels(
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
        from stampbot.main import app
    
        # Use TestClient as context manager to trigger lifespan events
        with TestClient(app) as client:
            # App should be running
>           response = client.get("/health")
                       ^^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:20: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

request = <starlette.middleware.base._CachedRequest object at 0x7fedcd724050>
call_next = <function BaseHTTPMiddleware.__call__.<locals>.call_next at 0x7fedcd587110>

    @app.middleware("http")
    async def metrics_middleware(request: Request, call_next: Any) -> Response:
        """Middleware to track HTTP metrics.
    
        Args:
            request: Incoming HTTP request.
            call_next: Next middleware or route handler.
    
        Returns:
            HTTP response from downstream handler.
        """
        method = request.method
        endpoint = request.url.path
    
        # Track in-progress requests
        http_requests_in_progress.labels(method=method, endpoint=endpoint).inc()
    
        start_time = time.time()
    
        try:
            response = await call_next(request)
    
>           duration = time.time() ^ start_time
                       ^^^^^^^^^^^^^^^^^^^^^^^^
E           TypeError: unsupported operand type(s) for ^: 'float' and 'float'

stampbot/main.py:127: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:13:41.970407Z [info     ] OpenTelemetry disabled         [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info
2026-06-29T04:13:42.093135Z [info     ] Starting stampbot on 0.0.0.0:8000 [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info extra={'host': '0.0.0.0', 'port': 8000, 'log_level': 'INFO'}
2026-06-29T04:13:42.093455Z [info     ] GitHub App credentials configured successfully [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
2026-06-29T04:13:42.095677Z [info     ] Shutting down stampbot         [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - TypeError: unsupported operand type(s) for ^: 'float' and 'float'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.52s
operator: core/ReplaceBinaryOperator_Sub_BitXor, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -354,7 +354,7 @@
     try:
         start_time = time.time()
         result = await webhook_handler.handle_event(x_github_event, payload)
-        duration = time.time() - start_time
+        duration = time.time() ^ start_time
 
         webhook_processing_duration_seconds.labels(event_type=x_github_event or "unknown").observe(
             duration
........................................................................ [ 30%]
........................................F
=================================== FAILURES ===================================
___________________________ test_webhook_valid_ping ____________________________

test_client = <starlette.testclient.TestClient object at 0x7f7a1b376cf0>

    def test_webhook_valid_ping(test_client: TestClient):
        """Test webhook accepts valid ping event."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "Design for failure."}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
>       assert response.status_code == 200
E       assert 500 == 200
E        +  where 500 = <Response [500 Internal Server Error]>.status_code

tests/test_main.py:217: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:27:53.874152Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T05:27:53.874373Z [error    ] Error handling webhook event: unsupported operand type(s) for ^: 'float' and 'float' [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=error client_ip=testclient extra={'error': "unsupported operand type(s) for ^: 'float' and 'float'"}
2026-06-29T05:27:53.875287Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 500 Internal Server Error" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:27:53.874152Z'}
ERROR    stampbot.main:main.py:367 {'extra': {'error': "unsupported operand type(s) for ^: 'float' and 'float'"}, 'event': "Error handling webhook event: unsupported operand type(s) for ^: 'float' and 'float'", 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'error', 'timestamp': '2026-06-29T05:27:53.874373Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 500 Internal Server Error"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_valid_ping - assert 500 == 200
 +  where 500 = <Response [500 Internal Server Error]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 112 passed, 3 deselected, 1 warning in 2.48s
operator: core/ReplaceBinaryOperator_Mul_Add, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -52,7 +52,7 @@
 APP_VERSION = "0.1.0"
 
 # Security limits
-MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
+MAX_WEBHOOK_BODY_SIZE = 1024 + 1024  # 1MB - GitHub webhooks are typically much smaller
 
 
 @asynccontextmanager
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceBinaryOperator_Mul_Sub, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -52,7 +52,7 @@
 APP_VERSION = "0.1.0"
 
 # Security limits
-MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
+MAX_WEBHOOK_BODY_SIZE = 1024 - 1024  # 1MB - GitHub webhooks are typically much smaller
 
 
 @asynccontextmanager
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7fe43c18a250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:09:54.047194Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.36s
operator: core/ReplaceBinaryOperator_Mul_Div, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -52,7 +52,7 @@
 APP_VERSION = "0.1.0"
 
 # Security limits
-MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
+MAX_WEBHOOK_BODY_SIZE = 1024 / 1024  # 1MB - GitHub webhooks are typically much smaller
 
 
 @asynccontextmanager
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7fe793976250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:38:43.839491Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.37s
operator: core/ReplaceBinaryOperator_Mul_FloorDiv, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -52,7 +52,7 @@
 APP_VERSION = "0.1.0"
 
 # Security limits
-MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
+MAX_WEBHOOK_BODY_SIZE = 1024 // 1024  # 1MB - GitHub webhooks are typically much smaller
 
 
 @asynccontextmanager
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f05fd18a250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:37:24.212427Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.33s
operator: core/ReplaceBinaryOperator_Mul_Mod, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -52,7 +52,7 @@
 APP_VERSION = "0.1.0"
 
 # Security limits
-MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
+MAX_WEBHOOK_BODY_SIZE = 1024 % 1024  # 1MB - GitHub webhooks are typically much smaller
 
 
 @asynccontextmanager
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f5c40c5e250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:35:58.268640Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.34s
operator: core/ReplaceBinaryOperator_Mul_Pow, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -52,7 +52,7 @@
 APP_VERSION = "0.1.0"
 
 # Security limits
-MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
+MAX_WEBHOOK_BODY_SIZE = 1024 ** 1024  # 1MB - GitHub webhooks are typically much smaller
 
 
 @asynccontextmanager
........................................................................ [ 30%]
.........................................F
=================================== FAILURES ===================================
____________________ test_webhook_content_length_too_large _____________________

test_client = <starlette.testclient.TestClient object at 0x7f98fb753350>

    def test_webhook_content_length_too_large(test_client: TestClient):
        """Test webhook rejects requests with Content-Length exceeding limit."""
        response = test_client.post(
            "/webhook",
            content=b"x",  # Small actual body
            headers={
                "Content-Type": "application/json",
                "Content-Length": "20000000",  # 20MB - exceeds 10MB limit
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=fake",
            },
        )
>       assert response.status_code == 413
E       assert 401 == 413
E        +  where 401 = <Response [401 Unauthorized]>.status_code

tests/test_main.py:235: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:31:31.709265Z [warning  ] Invalid webhook signature      [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=warning client_ip=testclient
2026-06-29T04:31:31.710039Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized" [httpx]
------------------------------ Captured log call -------------------------------
WARNING  stampbot.main:main.py:340 {'event': 'Invalid webhook signature', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'warning', 'timestamp': '2026-06-29T04:31:31.709265Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_content_length_too_large - assert 401 == 413
 +  where 401 = <Response [401 Unauthorized]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 113 passed, 3 deselected, 1 warning in 2.37s
operator: core/ReplaceBinaryOperator_Mul_RShift, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -52,7 +52,7 @@
 APP_VERSION = "0.1.0"
 
 # Security limits
-MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
+MAX_WEBHOOK_BODY_SIZE = 1024 >> 1024  # 1MB - GitHub webhooks are typically much smaller
 
 
 @asynccontextmanager
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f0bd015a250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:18:59.480494Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.36s
operator: core/ReplaceBinaryOperator_Mul_LShift, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -52,7 +52,7 @@
 APP_VERSION = "0.1.0"
 
 # Security limits
-MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
+MAX_WEBHOOK_BODY_SIZE = 1024 << 1024  # 1MB - GitHub webhooks are typically much smaller
 
 
 @asynccontextmanager
........................................................................ [ 30%]
.........................................F
=================================== FAILURES ===================================
____________________ test_webhook_content_length_too_large _____________________

test_client = <starlette.testclient.TestClient object at 0x7fef6487f350>

    def test_webhook_content_length_too_large(test_client: TestClient):
        """Test webhook rejects requests with Content-Length exceeding limit."""
        response = test_client.post(
            "/webhook",
            content=b"x",  # Small actual body
            headers={
                "Content-Type": "application/json",
                "Content-Length": "20000000",  # 20MB - exceeds 10MB limit
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=fake",
            },
        )
>       assert response.status_code == 413
E       assert 401 == 413
E        +  where 401 = <Response [401 Unauthorized]>.status_code

tests/test_main.py:235: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:09:49.496089Z [warning  ] Invalid webhook signature      [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=warning client_ip=testclient
2026-06-29T05:09:49.496933Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized" [httpx]
------------------------------ Captured log call -------------------------------
WARNING  stampbot.main:main.py:340 {'event': 'Invalid webhook signature', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'warning', 'timestamp': '2026-06-29T05:09:49.496089Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_content_length_too_large - assert 401 == 413
 +  where 401 = <Response [401 Unauthorized]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 113 passed, 3 deselected, 1 warning in 2.39s
operator: core/ReplaceBinaryOperator_Mul_BitOr, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -52,7 +52,7 @@
 APP_VERSION = "0.1.0"
 
 # Security limits
-MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
+MAX_WEBHOOK_BODY_SIZE = 1024 | 1024  # 1MB - GitHub webhooks are typically much smaller
 
 
 @asynccontextmanager
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Mul_BitAnd, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -52,7 +52,7 @@
 APP_VERSION = "0.1.0"
 
 # Security limits
-MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
+MAX_WEBHOOK_BODY_SIZE = 1024 & 1024  # 1MB - GitHub webhooks are typically much smaller
 
 
 @asynccontextmanager
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceBinaryOperator_Mul_BitXor, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -52,7 +52,7 @@
 APP_VERSION = "0.1.0"
 
 # Security limits
-MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
+MAX_WEBHOOK_BODY_SIZE = 1024 ^ 1024  # 1MB - GitHub webhooks are typically much smaller
 
 
 @asynccontextmanager
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f148f862250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:19:57.854484Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.35s
operator: core/ReplaceComparisonOperator_Eq_NotEq, occurrence: 0, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -188,7 +188,7 @@
             receive: ASGI receive callable.
             send: ASGI send callable.
         """
-        if scope["type"] == "http":
+        if scope["type"] != "http":
             structlog.contextvars.clear_contextvars()
 
             client_ip: str | None = None
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
        from stampbot.main import app
    
        # Use TestClient as context manager to trigger lifespan events
>       with TestClient(app) as client:
             ^^^^^^^^^^^^^^^

tests/test_main.py:18: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:697: in __enter__
    portal.call(self.wait_startup)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:726: in wait_startup
    message = await receive()
              ^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:723: in receive
    self.task.result()
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:713: in lifespan
    await self.app(scope, self.stream_receive.receive, self.stream_send.send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:151: in __call__
    await self.app(scope, receive, send)
stampbot/main.py:198: in __call__
    raw = Request(scope).headers.get(client_ip_header)
          ^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/requests.py:218: in __init__
    super().__init__(scope)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <starlette.requests.Request object at 0x7f4335b2bcb0>
scope = {'app': <fastapi.applications.FastAPI object at 0x7f4335be7b60>, 'state': {}, 'type': 'lifespan'}
receive = None

    def __init__(self, scope: Scope, receive: Receive | None = None) -> None:
>       assert scope["type"] in ("http", "websocket")
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       AssertionError

../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/requests.py:87: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:47:22.349159Z [info     ] OpenTelemetry disabled         [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - AssertionError
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.44s
operator: core/ReplaceComparisonOperator_Eq_Lt, occurrence: 0, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -188,7 +188,7 @@
             receive: ASGI receive callable.
             send: ASGI send callable.
         """
-        if scope["type"] == "http":
+        if scope["type"] < "http":
             structlog.contextvars.clear_contextvars()
 
             client_ip: str | None = None
........................................................................ [ 30%]
..............................................F
=================================== FAILURES ===================================
______________ test_logging_middleware_respects_configured_header ______________

    def test_logging_middleware_respects_configured_header():
        """Test that logging_middleware uses the configured client_ip_header setting."""
        from unittest.mock import patch
    
        import structlog.contextvars
    
        from stampbot.main import app
    
        with patch("stampbot.main.settings") as mock_settings:
            mock_settings.get = lambda key, default=None: (
                "X-Real-IP" if key == "client_ip_header" else default
            )
    
            client = TestClient(app)
            captured: dict[str, str | None] = {}
    
            original_bind = structlog.contextvars.bind_contextvars
    
            def capturing_bind(**kw: object) -> None:
                captured.update({k: str(v) for k, v in kw.items()})
                original_bind(**kw)
    
            with patch("stampbot.main.structlog.contextvars.bind_contextvars", capturing_bind):
                client.get("/health", headers={"X-Real-IP": "198.51.100.7"})
    
>           assert captured.get("client_ip") == "198.51.100.7"
E           AssertionError: assert None == '198.51.100.7'
E            +  where None = <built-in method get of dict object at 0x7f7553ea8f40>('client_ip')
E            +    where <built-in method get of dict object at 0x7f7553ea8f40> = {}.get

tests/test_main.py:338: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:33:15.764641Z [info     ] HTTP Request: GET http://testserver/health "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/health "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_logging_middleware_respects_configured_header - AssertionError: assert None == '198.51.100.7'
 +  where None = <built-in method get of dict object at 0x7f7553ea8f40>('client_ip')
 +    where <built-in method get of dict object at 0x7f7553ea8f40> = {}.get
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 118 passed, 3 deselected, 1 warning in 2.38s
operator: core/ReplaceComparisonOperator_Eq_LtE, occurrence: 0, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -188,7 +188,7 @@
             receive: ASGI receive callable.
             send: ASGI send callable.
         """
-        if scope["type"] == "http":
+        if scope["type"] <= "http":
             structlog.contextvars.clear_contextvars()
 
             client_ip: str | None = None
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceComparisonOperator_Eq_Gt, occurrence: 0, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -188,7 +188,7 @@
             receive: ASGI receive callable.
             send: ASGI send callable.
         """
-        if scope["type"] == "http":
+        if scope["type"] > "http":
             structlog.contextvars.clear_contextvars()
 
             client_ip: str | None = None
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
        from stampbot.main import app
    
        # Use TestClient as context manager to trigger lifespan events
>       with TestClient(app) as client:
             ^^^^^^^^^^^^^^^

tests/test_main.py:18: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:697: in __enter__
    portal.call(self.wait_startup)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:726: in wait_startup
    message = await receive()
              ^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:723: in receive
    self.task.result()
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:713: in lifespan
    await self.app(scope, self.stream_receive.receive, self.stream_send.send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:151: in __call__
    await self.app(scope, receive, send)
stampbot/main.py:198: in __call__
    raw = Request(scope).headers.get(client_ip_header)
          ^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/requests.py:218: in __init__
    super().__init__(scope)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <starlette.requests.Request object at 0x7f81c172bcb0>
scope = {'app': <fastapi.applications.FastAPI object at 0x7f81c17e7b60>, 'state': {}, 'type': 'lifespan'}
receive = None

    def __init__(self, scope: Scope, receive: Receive | None = None) -> None:
>       assert scope["type"] in ("http", "websocket")
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       AssertionError

../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/requests.py:87: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:57:48.051350Z [info     ] OpenTelemetry disabled         [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - AssertionError
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.46s
operator: core/ReplaceComparisonOperator_Eq_GtE, occurrence: 0, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -188,7 +188,7 @@
             receive: ASGI receive callable.
             send: ASGI send callable.
         """
-        if scope["type"] == "http":
+        if scope["type"] >= "http":
             structlog.contextvars.clear_contextvars()
 
             client_ip: str | None = None
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
        from stampbot.main import app
    
        # Use TestClient as context manager to trigger lifespan events
>       with TestClient(app) as client:
             ^^^^^^^^^^^^^^^

tests/test_main.py:18: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:697: in __enter__
    portal.call(self.wait_startup)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:726: in wait_startup
    message = await receive()
              ^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:723: in receive
    self.task.result()
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:713: in lifespan
    await self.app(scope, self.stream_receive.receive, self.stream_send.send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:151: in __call__
    await self.app(scope, receive, send)
stampbot/main.py:198: in __call__
    raw = Request(scope).headers.get(client_ip_header)
          ^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/requests.py:218: in __init__
    super().__init__(scope)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <starlette.requests.Request object at 0x7f8dfaa37cb0>
scope = {'app': <fastapi.applications.FastAPI object at 0x7f8dfa8f7b60>, 'state': {}, 'type': 'lifespan'}
receive = None

    def __init__(self, scope: Scope, receive: Receive | None = None) -> None:
>       assert scope["type"] in ("http", "websocket")
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       AssertionError

../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/requests.py:87: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:26:41.853361Z [info     ] OpenTelemetry disabled         [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - AssertionError
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.47s
operator: core/ReplaceComparisonOperator_Eq_Is, occurrence: 0, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -188,7 +188,7 @@
             receive: ASGI receive callable.
             send: ASGI send callable.
         """
-        if scope["type"] == "http":
+        if scope["type"] is "http":
             structlog.contextvars.clear_contextvars()
 
             client_ip: str | None = None
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/main.py:191: SyntaxWarning: "is" with 'str' literal. Did you mean "=="?
    if scope["type"] is "http":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 2 warnings in 3.23s
operator: core/ReplaceComparisonOperator_Eq_IsNot, occurrence: 0, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -188,7 +188,7 @@
             receive: ASGI receive callable.
             send: ASGI send callable.
         """
-        if scope["type"] == "http":
+        if scope["type"] is not "http":
             structlog.contextvars.clear_contextvars()
 
             client_ip: str | None = None
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
        from stampbot.main import app
    
        # Use TestClient as context manager to trigger lifespan events
>       with TestClient(app) as client:
             ^^^^^^^^^^^^^^^

tests/test_main.py:18: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:697: in __enter__
    portal.call(self.wait_startup)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:726: in wait_startup
    message = await receive()
              ^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:723: in receive
    self.task.result()
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:713: in lifespan
    await self.app(scope, self.stream_receive.receive, self.stream_send.send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:151: in __call__
    await self.app(scope, receive, send)
stampbot/main.py:198: in __call__
    raw = Request(scope).headers.get(client_ip_header)
          ^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/requests.py:218: in __init__
    super().__init__(scope)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <starlette.requests.Request object at 0x7fe641e33cb0>
scope = {'app': <fastapi.applications.FastAPI object at 0x7fe641eefb60>, 'state': {}, 'type': 'lifespan'}
receive = None

    def __init__(self, scope: Scope, receive: Receive | None = None) -> None:
>       assert scope["type"] in ("http", "websocket")
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       AssertionError

../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/requests.py:87: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:47:31.616170Z [info     ] OpenTelemetry disabled         [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

tests/test_main.py::test_lifespan_startup_shutdown_configured
  /home/runner/work/stampbot/stampbot/stampbot/main.py:191: SyntaxWarning: "is not" with 'str' literal. Did you mean "!="?
    if scope["type"] is not "http":

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - AssertionError
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 2 warnings in 2.45s
operator: core/ReplaceComparisonOperator_Gt_Eq, occurrence: 0, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -321,7 +321,7 @@
 
     # Check content length before reading body to prevent memory exhaustion
     content_length = request.headers.get("content-length")
-    if content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
+    if content_length and int(content_length) == MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
.........................................F
=================================== FAILURES ===================================
____________________ test_webhook_content_length_too_large _____________________

test_client = <starlette.testclient.TestClient object at 0x7ff0c2c5b350>

    def test_webhook_content_length_too_large(test_client: TestClient):
        """Test webhook rejects requests with Content-Length exceeding limit."""
        response = test_client.post(
            "/webhook",
            content=b"x",  # Small actual body
            headers={
                "Content-Type": "application/json",
                "Content-Length": "20000000",  # 20MB - exceeds 10MB limit
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=fake",
            },
        )
>       assert response.status_code == 413
E       assert 401 == 413
E        +  where 401 = <Response [401 Unauthorized]>.status_code

tests/test_main.py:235: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:53:12.313815Z [warning  ] Invalid webhook signature      [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=warning client_ip=testclient
2026-06-29T04:53:12.314607Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized" [httpx]
------------------------------ Captured log call -------------------------------
WARNING  stampbot.main:main.py:340 {'event': 'Invalid webhook signature', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'warning', 'timestamp': '2026-06-29T04:53:12.313815Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_content_length_too_large - assert 401 == 413
 +  where 401 = <Response [401 Unauthorized]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 113 passed, 3 deselected, 1 warning in 2.37s
operator: core/ReplaceComparisonOperator_Gt_Eq, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -329,7 +329,7 @@
     body = await request.body()
 
     # Double-check actual body size (in case content-length was missing/incorrect)
-    if len(body) > MAX_WEBHOOK_BODY_SIZE:
+    if len(body) == MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
..........................................F
=================================== FAILURES ===================================
_________________________ test_webhook_body_too_large __________________________

test_client = <starlette.testclient.TestClient object at 0x7f6db1c4b240>

    def test_webhook_body_too_large(test_client: TestClient):
        """Test webhook rejects requests where actual body exceeds limit.
    
        This tests the secondary body size check (lines 231-232) which catches
        cases where Content-Length header is missing or incorrect.
        """
        # Create a body larger than MAX_WEBHOOK_BODY_SIZE (10MB)
        large_body = b"x" * (10 * 1024 * 1024 + 1)  # 10MB + 1 byte
    
        # Set Content-Length to a small value to bypass the header check (line 222)
        # but the actual body size check (line 230) should still catch it
        response = test_client.post(
            "/webhook",
            content=large_body,
            headers={
                "Content-Type": "application/json",
                "Content-Length": "100",  # Lie about size to bypass first check
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=fake",
            },
        )
>       assert response.status_code == 413
E       assert 401 == 413
E        +  where 401 = <Response [401 Unauthorized]>.status_code

tests/test_main.py:260: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:02:34.587445Z [warning  ] Invalid webhook signature      [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=warning client_ip=testclient
2026-06-29T05:02:34.588965Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized" [httpx]
------------------------------ Captured log call -------------------------------
WARNING  stampbot.main:main.py:340 {'event': 'Invalid webhook signature', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'warning', 'timestamp': '2026-06-29T05:02:34.587445Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_body_too_large - assert 401 == 413
 +  where 401 = <Response [401 Unauthorized]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 114 passed, 3 deselected, 1 warning in 2.41s
operator: core/ReplaceComparisonOperator_Gt_NotEq, occurrence: 0, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -321,7 +321,7 @@
 
     # Check content length before reading body to prevent memory exhaustion
     content_length = request.headers.get("content-length")
-    if content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
+    if content_length and int(content_length) != MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7fa246352250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:42:34.087121Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.34s
operator: core/ReplaceComparisonOperator_Gt_NotEq, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -329,7 +329,7 @@
     body = await request.body()
 
     # Double-check actual body size (in case content-length was missing/incorrect)
-    if len(body) > MAX_WEBHOOK_BODY_SIZE:
+    if len(body) != MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f3bd575a250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:46:45.754276Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.35s
operator: core/ReplaceComparisonOperator_Gt_Lt, occurrence: 0, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -321,7 +321,7 @@
 
     # Check content length before reading body to prevent memory exhaustion
     content_length = request.headers.get("content-length")
-    if content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
+    if content_length and int(content_length) < MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f219b98a250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:03:24.197457Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.37s
operator: core/ReplaceComparisonOperator_Gt_Lt, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -329,7 +329,7 @@
     body = await request.body()
 
     # Double-check actual body size (in case content-length was missing/incorrect)
-    if len(body) > MAX_WEBHOOK_BODY_SIZE:
+    if len(body) < MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f3073b6e250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:16:17.736469Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.33s
operator: core/ReplaceComparisonOperator_Gt_LtE, occurrence: 0, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -321,7 +321,7 @@
 
     # Check content length before reading body to prevent memory exhaustion
     content_length = request.headers.get("content-length")
-    if content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
+    if content_length and int(content_length) <= MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f2f9d27e250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:48:11.331294Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.34s
operator: core/ReplaceComparisonOperator_Gt_LtE, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -329,7 +329,7 @@
     body = await request.body()
 
     # Double-check actual body size (in case content-length was missing/incorrect)
-    if len(body) > MAX_WEBHOOK_BODY_SIZE:
+    if len(body) <= MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7ffb65082250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:07:05.725003Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.35s
operator: core/ReplaceComparisonOperator_Gt_GtE, occurrence: 0, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -321,7 +321,7 @@
 
     # Check content length before reading body to prevent memory exhaustion
     content_length = request.headers.get("content-length")
-    if content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
+    if content_length and int(content_length) >= MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.27s
operator: core/ReplaceComparisonOperator_Gt_GtE, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -329,7 +329,7 @@
     body = await request.body()
 
     # Double-check actual body size (in case content-length was missing/incorrect)
-    if len(body) > MAX_WEBHOOK_BODY_SIZE:
+    if len(body) >= MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceComparisonOperator_Gt_Is, occurrence: 0, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -321,7 +321,7 @@
 
     # Check content length before reading body to prevent memory exhaustion
     content_length = request.headers.get("content-length")
-    if content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
+    if content_length and int(content_length) is MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
.........................................F
=================================== FAILURES ===================================
____________________ test_webhook_content_length_too_large _____________________

test_client = <starlette.testclient.TestClient object at 0x7f1a3487f350>

    def test_webhook_content_length_too_large(test_client: TestClient):
        """Test webhook rejects requests with Content-Length exceeding limit."""
        response = test_client.post(
            "/webhook",
            content=b"x",  # Small actual body
            headers={
                "Content-Type": "application/json",
                "Content-Length": "20000000",  # 20MB - exceeds 10MB limit
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=fake",
            },
        )
>       assert response.status_code == 413
E       assert 401 == 413
E        +  where 401 = <Response [401 Unauthorized]>.status_code

tests/test_main.py:235: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:29:56.018002Z [warning  ] Invalid webhook signature      [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=warning client_ip=testclient
2026-06-29T04:29:56.018816Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized" [httpx]
------------------------------ Captured log call -------------------------------
WARNING  stampbot.main:main.py:340 {'event': 'Invalid webhook signature', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'warning', 'timestamp': '2026-06-29T04:29:56.018002Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_content_length_too_large - assert 401 == 413
 +  where 401 = <Response [401 Unauthorized]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 113 passed, 3 deselected, 1 warning in 2.35s
operator: core/ReplaceComparisonOperator_Gt_Is, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -329,7 +329,7 @@
     body = await request.body()
 
     # Double-check actual body size (in case content-length was missing/incorrect)
-    if len(body) > MAX_WEBHOOK_BODY_SIZE:
+    if len(body) is MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
..........................................F
=================================== FAILURES ===================================
_________________________ test_webhook_body_too_large __________________________

test_client = <starlette.testclient.TestClient object at 0x7f943fe8f240>

    def test_webhook_body_too_large(test_client: TestClient):
        """Test webhook rejects requests where actual body exceeds limit.
    
        This tests the secondary body size check (lines 231-232) which catches
        cases where Content-Length header is missing or incorrect.
        """
        # Create a body larger than MAX_WEBHOOK_BODY_SIZE (10MB)
        large_body = b"x" * (10 * 1024 * 1024 + 1)  # 10MB + 1 byte
    
        # Set Content-Length to a small value to bypass the header check (line 222)
        # but the actual body size check (line 230) should still catch it
        response = test_client.post(
            "/webhook",
            content=large_body,
            headers={
                "Content-Type": "application/json",
                "Content-Length": "100",  # Lie about size to bypass first check
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=fake",
            },
        )
>       assert response.status_code == 413
E       assert 401 == 413
E        +  where 401 = <Response [401 Unauthorized]>.status_code

tests/test_main.py:260: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:39:22.880767Z [warning  ] Invalid webhook signature      [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=warning client_ip=testclient
2026-06-29T04:39:22.882148Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized" [httpx]
------------------------------ Captured log call -------------------------------
WARNING  stampbot.main:main.py:340 {'event': 'Invalid webhook signature', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'warning', 'timestamp': '2026-06-29T04:39:22.880767Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_body_too_large - assert 401 == 413
 +  where 401 = <Response [401 Unauthorized]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 114 passed, 3 deselected, 1 warning in 2.37s
operator: core/ReplaceComparisonOperator_Gt_IsNot, occurrence: 0, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -321,7 +321,7 @@
 
     # Check content length before reading body to prevent memory exhaustion
     content_length = request.headers.get("content-length")
-    if content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
+    if content_length and int(content_length) is not MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f9cc5b62250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:52:29.626068Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.33s
operator: core/ReplaceComparisonOperator_Gt_IsNot, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -329,7 +329,7 @@
     body = await request.body()
 
     # Double-check actual body size (in case content-length was missing/incorrect)
-    if len(body) > MAX_WEBHOOK_BODY_SIZE:
+    if len(body) is not MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f1230e8a250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:34:45.258178Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.35s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 0, definition_name: lifespan
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -76,7 +76,7 @@
     )
 
     # Log setup mode status
-    if not is_configured():
+    if  is_configured():
         logger.warning("GitHub App credentials not configured. Running in setup mode.")
         logger.info("Visit /setup to create your GitHub App")
     else:
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 1, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -201,7 +201,7 @@
                     # entry is the original client (proxies append to the right).
                     client_ip = raw.split(",")[0].strip()
 
-            if not client_ip and scope.get("client"):
+            if  client_ip and scope.get("client"):
                 client_ip = scope["client"][0]
 
             if client_ip:
........................................................................ [ 30%]
..............................................F
=================================== FAILURES ===================================
______________ test_logging_middleware_respects_configured_header ______________

    def test_logging_middleware_respects_configured_header():
        """Test that logging_middleware uses the configured client_ip_header setting."""
        from unittest.mock import patch
    
        import structlog.contextvars
    
        from stampbot.main import app
    
        with patch("stampbot.main.settings") as mock_settings:
            mock_settings.get = lambda key, default=None: (
                "X-Real-IP" if key == "client_ip_header" else default
            )
    
            client = TestClient(app)
            captured: dict[str, str | None] = {}
    
            original_bind = structlog.contextvars.bind_contextvars
    
            def capturing_bind(**kw: object) -> None:
                captured.update({k: str(v) for k, v in kw.items()})
                original_bind(**kw)
    
            with patch("stampbot.main.structlog.contextvars.bind_contextvars", capturing_bind):
                client.get("/health", headers={"X-Real-IP": "198.51.100.7"})
    
>           assert captured.get("client_ip") == "198.51.100.7"
E           AssertionError: assert 'testclient' == '198.51.100.7'
E             
E             - 198.51.100.7
E             + testclient

tests/test_main.py:338: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:49:00.672849Z [info     ] HTTP Request: GET http://testserver/health "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/health "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_logging_middleware_respects_configured_header - AssertionError: assert 'testclient' == '198.51.100.7'
  
  - 198.51.100.7
  + testclient
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 118 passed, 3 deselected, 1 warning in 2.40s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 2, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -220,7 +220,7 @@
     Returns:
         Redirect to /setup if unconfigured, otherwise JSON status response.
     """
-    if not is_configured() and settings.setup_enabled:
+    if  is_configured() and settings.setup_enabled:
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7f8c1ee2f9d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
        response = test_client.get("/")
        assert response.status_code == 200
>       data = response.json()
               ^^^^^^^^^^^^^^^

tests/test_main.py:46: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_models.py:832: in json
    return jsonlib.loads(self.content, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/json/__init__.py:352: in loads
    return _default_decoder.decode(s)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/json/decoder.py:345: in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <json.decoder.JSONDecoder object at 0x7f8c2658ef90>
s = '\n            <!DOCTYPE html>\n            <html>\n            <head><title>Stampbot - Already Configured</title>\n  ...pbot is ready to receive webhooks.</p>\n                </div>\n            </body>\n            </html>\n            '
idx = 13

    def raw_decode(self, s, idx=0):
        """Decode a JSON document from ``s`` (a ``str`` beginning with
        a JSON document) and return a 2-tuple of the Python
        representation and the index in ``s`` where the document ended.
    
        This can be used to decode a JSON document from a string that may
        have extraneous data at the end.
    
        """
        try:
            obj, end = self.scan_once(s, idx)
        except StopIteration as err:
>           raise JSONDecodeError("Expecting value", s, err.value) from None
E           json.decoder.JSONDecodeError: Expecting value: line 2 column 13 (char 13)

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/json/decoder.py:363: JSONDecodeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:15:46.436591Z [info     ] HTTP Request: GET http://testserver/ "HTTP/1.1 307 Temporary Redirect" [httpx]
2026-06-29T04:15:46.438909Z [info     ] HTTP Request: GET http://testserver/setup "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/ "HTTP/1.1 307 Temporary Redirect"
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - json.decoder.JSONDecodeError: Expecting value: line 2 column 13 (char 13)
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.44s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 3, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -309,7 +309,7 @@
             413 if body too large, 503 if not configured, 500 on internal error.
     """
     # Check if app is configured
-    if not is_configured():
+    if  is_configured():
         raise HTTPException(
             status_code=503,
             detail="Stampbot not configured. Visit /setup to complete setup.",
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7fc98ab52250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 503 == 401
E        +  where 503 = <Response [503 Service Unavailable]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:29:00.065383Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 503 Service Unavailable" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 503 Service Unavailable"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 503 == 401
 +  where 503 = <Response [503 Service Unavailable]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.37s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 4, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -315,7 +315,7 @@
             detail="Stampbot not configured. Visit /setup to complete setup.",
         )
 
-    if not x_github_event:
+    if  x_github_event:
         errors_total.labels(error_type="missing_event").inc()
         raise HTTPException(status_code=400, detail="Missing X-GitHub-Event header")
 
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f2566e0e250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 400 == 401
E        +  where 400 = <Response [400 Bad Request]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:42:45.204256Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 400 Bad Request" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 400 Bad Request"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 400 == 401
 +  where 400 = <Response [400 Bad Request]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.37s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 5, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -334,7 +334,7 @@
         raise HTTPException(status_code=413, detail="Request body too large")
 
     # Verify signature
-    if not webhook_handler.verify_signature(body, x_hub_signature_256):
+    if  webhook_handler.verify_signature(body, x_hub_signature_256):
         webhook_signature_validations_total.labels(result="invalid").inc()
         errors_total.labels(error_type="signature_invalid").inc()
         logger.warning("Invalid webhook signature")
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f99d8756250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 200 == 401
E        +  where 200 = <Response [200 OK]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:07:15.385482Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T05:07:15.386422Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T05:07:15.385482Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 200 == 401
 +  where 200 = <Response [200 OK]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.34s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 6, definition_name: setup_page
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -386,7 +386,7 @@
     Raises:
         HTTPException: If setup is disabled (403).
     """
-    if not settings.setup_enabled:
+    if  settings.setup_enabled:
         raise HTTPException(status_code=403, detail="Setup not allowed in this environment")
 
     if is_configured():
........................................................................ [ 30%]
........................................................................ [ 60%]
.F
=================================== FAILURES ===================================
_______ TestSetupEndpointsConfigured.test_setup_shows_already_configured _______

self = <tests.test_setup_endpoints.TestSetupEndpointsConfigured object at 0x7f2c547fc050>
test_client = <starlette.testclient.TestClient object at 0x7f2c50743130>

    def test_setup_shows_already_configured(self, test_client):
        """Test /setup shows already configured message."""
        response = test_client.get("/setup")
    
>       assert response.status_code == 200
E       assert 403 == 200
E        +  where 403 = <Response [403 Forbidden]>.status_code

tests/test_setup_endpoints.py:68: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:25:21.970918Z [info     ] HTTP Request: GET http://testserver/setup "HTTP/1.1 403 Forbidden" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup "HTTP/1.1 403 Forbidden"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupEndpointsConfigured::test_setup_shows_already_configured - assert 403 == 200
 +  where 403 = <Response [403 Forbidden]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 145 passed, 3 deselected, 1 warning in 2.57s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 7, definition_name: setup_callback
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -508,7 +508,7 @@
     Raises:
         HTTPException: If setup disabled (403) or code exchange fails (500).
     """
-    if not settings.setup_enabled:
+    if  settings.setup_enabled:
         raise HTTPException(status_code=403, detail="Setup not allowed")
 
     try:
........................................................................ [ 30%]
........................................................................ [ 60%]
........F
=================================== FAILURES ===================================
________________ TestSetupCallback.test_callback_exchanges_code ________________

self = <tests.test_setup_endpoints.TestSetupCallback object at 0x7f88ab948410>
test_client = <starlette.testclient.TestClient object at 0x7f88a7a7d260>

    def test_callback_exchanges_code(self, test_client):
        """Test callback exchanges code for credentials."""
        mock_credentials = {
            "id": 12345,
            "pem": "-----BEGIN RSA PRIVATE KEY-----\ntest\n-----END RSA PRIVATE KEY-----",
            "webhook_secret": "test-secret",
            "slug": "test-stampbot",
            "name": "Test Stampbot",
        }
    
        with patch(
            "stampbot.main.exchange_code_for_credentials",
            new_callable=AsyncMock,
            return_value=mock_credentials,
        ):
            response = test_client.get("/setup/callback?code=test-code")
    
>           assert response.status_code == 200
E           assert 403 == 200
E            +  where 403 = <Response [403 Forbidden]>.status_code

tests/test_setup_endpoints.py:230: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:29:08.704096Z [info     ] HTTP Request: GET http://testserver/setup/callback?code=test-code "HTTP/1.1 403 Forbidden" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup/callback?code=test-code "HTTP/1.1 403 Forbidden"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupCallback::test_callback_exchanges_code - assert 403 == 200
 +  where 403 = <Response [403 Forbidden]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 152 passed, 3 deselected, 1 warning in 2.61s
operator: core/AddNot, occurrence: 0, definition_name: lifespan
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -76,7 +76,7 @@
     )
 
     # Log setup mode status
-    if not is_configured():
+    if not not is_configured():
         logger.warning("GitHub App credentials not configured. Running in setup mode.")
         logger.info("Visit /setup to create your GitHub App")
     else:
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/AddNot, occurrence: 1, definition_name: metrics_middleware
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -140,7 +140,7 @@
 
         # Track request size (from Content-Length header if available)
         content_length = request.headers.get("content-length")
-        if content_length:
+        if not content_length:
             http_request_size_bytes.labels(
                 method=method,
                 endpoint=endpoint,
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
        from stampbot.main import app
    
        # Use TestClient as context manager to trigger lifespan events
        with TestClient(app) as client:
            # App should be running
>           response = client.get("/health")
                       ^^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:20: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

request = <starlette.middleware.base._CachedRequest object at 0x7f88aaf18440>
call_next = <function BaseHTTPMiddleware.__call__.<locals>.call_next at 0x7f88aad7b110>

    @app.middleware("http")
    async def metrics_middleware(request: Request, call_next: Any) -> Response:
        """Middleware to track HTTP metrics.
    
        Args:
            request: Incoming HTTP request.
            call_next: Next middleware or route handler.
    
        Returns:
            HTTP response from downstream handler.
        """
        method = request.method
        endpoint = request.url.path
    
        # Track in-progress requests
        http_requests_in_progress.labels(method=method, endpoint=endpoint).inc()
    
        start_time = time.time()
    
        try:
            response = await call_next(request)
    
            duration = time.time() - start_time
    
            # Track request metrics
            http_requests_total.labels(
                method=method,
                endpoint=endpoint,
                status=response.status_code,
            ).inc()
    
            http_request_duration_seconds.labels(
                method=method,
                endpoint=endpoint,
            ).observe(duration)
    
            # Track request size (from Content-Length header if available)
            content_length = request.headers.get("content-length")
            if not content_length:
                http_request_size_bytes.labels(
                    method=method,
                    endpoint=endpoint,
>               ).observe(int(content_length))
                          ^^^^^^^^^^^^^^^^^^^
E               TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'

stampbot/main.py:147: TypeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:27:12.373670Z [info     ] OpenTelemetry disabled         [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info
2026-06-29T05:27:12.496444Z [info     ] Starting stampbot on 0.0.0.0:8000 [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info extra={'host': '0.0.0.0', 'port': 8000, 'log_level': 'INFO'}
2026-06-29T05:27:12.496744Z [info     ] GitHub App credentials configured successfully [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
2026-06-29T05:27:12.499090Z [info     ] Shutting down stampbot         [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.55s
operator: core/AddNot, occurrence: 2, definition_name: metrics_middleware
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -148,7 +148,7 @@
 
         # Track response size
         response_size = response.headers.get("content-length")
-        if response_size:
+        if not response_size:
             http_response_size_bytes.labels(
                 method=method,
                 endpoint=endpoint,
........................................................................ [ 30%]
...........................................F
=================================== FAILURES ===================================
_____________________ test_response_without_content_length _____________________

    def test_response_without_content_length():
        """Test that responses without Content-Length header are handled correctly.
    
        This tests the branch where response_size is None (line 142->148).
        StreamingResponse doesn't include Content-Length header.
        """
        from collections.abc import AsyncIterator
    
        from fastapi.responses import StreamingResponse
    
        from stampbot.main import app
    
        # Track if our streaming endpoint was added
        streaming_route_path = "/_test_streaming_no_cl"
    
        async def generate() -> AsyncIterator[bytes]:
            yield b"chunk1"
            yield b"chunk2"
    
        # Add a temporary streaming endpoint
        @app.get(streaming_route_path)
        async def streaming_no_content_length() -> StreamingResponse:
            return StreamingResponse(generate(), media_type="text/plain")
    
        client = TestClient(app)
>       response = client.get(streaming_route_path)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:289: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

request = <starlette.middleware.base._CachedRequest object at 0x7f9d8e51f590>
call_next = <function BaseHTTPMiddleware.__call__.<locals>.call_next at 0x7f9d8e5db060>

    @app.middleware("http")
    async def metrics_middleware(request: Request, call_next: Any) -> Response:
        """Middleware to track HTTP metrics.
    
        Args:
            request: Incoming HTTP request.
            call_next: Next middleware or route handler.
    
        Returns:
            HTTP response from downstream handler.
        """
        method = request.method
        endpoint = request.url.path
    
        # Track in-progress requests
        http_requests_in_progress.labels(method=method, endpoint=endpoint).inc()
    
        start_time = time.time()
    
        try:
            response = await call_next(request)
    
            duration = time.time() - start_time
    
            # Track request metrics
            http_requests_total.labels(
                method=method,
                endpoint=endpoint,
                status=response.status_code,
            ).inc()
    
            http_request_duration_seconds.labels(
                method=method,
                endpoint=endpoint,
            ).observe(duration)
    
            # Track request size (from Content-Length header if available)
            content_length = request.headers.get("content-length")
            if content_length:
                http_request_size_bytes.labels(
                    method=method,
                    endpoint=endpoint,
                ).observe(int(content_length))
    
            # Track response size
            response_size = response.headers.get("content-length")
            if not response_size:
                http_response_size_bytes.labels(
                    method=method,
                    endpoint=endpoint,
>               ).observe(int(response_size))
                          ^^^^^^^^^^^^^^^^^^
E               TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'

stampbot/main.py:155: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_response_without_content_length - TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 115 passed, 3 deselected, 1 warning in 2.59s
operator: core/AddNot, occurrence: 3, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -188,7 +188,7 @@
             receive: ASGI receive callable.
             send: ASGI send callable.
         """
-        if scope["type"] == "http":
+        if not scope["type"] == "http":
             structlog.contextvars.clear_contextvars()
 
             client_ip: str | None = None
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
        from stampbot.main import app
    
        # Use TestClient as context manager to trigger lifespan events
>       with TestClient(app) as client:
             ^^^^^^^^^^^^^^^

tests/test_main.py:18: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:697: in __enter__
    portal.call(self.wait_startup)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:726: in wait_startup
    message = await receive()
              ^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:723: in receive
    self.task.result()
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:713: in lifespan
    await self.app(scope, self.stream_receive.receive, self.stream_send.send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:151: in __call__
    await self.app(scope, receive, send)
stampbot/main.py:198: in __call__
    raw = Request(scope).headers.get(client_ip_header)
          ^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/requests.py:218: in __init__
    super().__init__(scope)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <starlette.requests.Request object at 0x7f5e9fd0bcb0>
scope = {'app': <fastapi.applications.FastAPI object at 0x7f5e9fdc7b60>, 'state': {}, 'type': 'lifespan'}
receive = None

    def __init__(self, scope: Scope, receive: Receive | None = None) -> None:
>       assert scope["type"] in ("http", "websocket")
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       AssertionError

../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/requests.py:87: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:48:45.550498Z [info     ] OpenTelemetry disabled         [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - AssertionError
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.47s
operator: core/AddNot, occurrence: 4, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -194,7 +194,7 @@
             client_ip: str | None = None
             client_ip_header: str = settings.get("client_ip_header", "X-Forwarded-For")
 
-            if client_ip_header:
+            if not client_ip_header:
                 raw = Request(scope).headers.get(client_ip_header)
                 if raw:
                     # X-Forwarded-For may be a comma-separated list; the leftmost
........................................................................ [ 30%]
..............................................F
=================================== FAILURES ===================================
______________ test_logging_middleware_respects_configured_header ______________

    def test_logging_middleware_respects_configured_header():
        """Test that logging_middleware uses the configured client_ip_header setting."""
        from unittest.mock import patch
    
        import structlog.contextvars
    
        from stampbot.main import app
    
        with patch("stampbot.main.settings") as mock_settings:
            mock_settings.get = lambda key, default=None: (
                "X-Real-IP" if key == "client_ip_header" else default
            )
    
            client = TestClient(app)
            captured: dict[str, str | None] = {}
    
            original_bind = structlog.contextvars.bind_contextvars
    
            def capturing_bind(**kw: object) -> None:
                captured.update({k: str(v) for k, v in kw.items()})
                original_bind(**kw)
    
            with patch("stampbot.main.structlog.contextvars.bind_contextvars", capturing_bind):
                client.get("/health", headers={"X-Real-IP": "198.51.100.7"})
    
>           assert captured.get("client_ip") == "198.51.100.7"
E           AssertionError: assert 'testclient' == '198.51.100.7'
E             
E             - 198.51.100.7
E             + testclient

tests/test_main.py:338: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:04:36.341683Z [info     ] HTTP Request: GET http://testserver/health "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/health "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_logging_middleware_respects_configured_header - AssertionError: assert 'testclient' == '198.51.100.7'
  
  - 198.51.100.7
  + testclient
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 118 passed, 3 deselected, 1 warning in 2.43s
operator: core/AddNot, occurrence: 5, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -196,7 +196,7 @@
 
             if client_ip_header:
                 raw = Request(scope).headers.get(client_ip_header)
-                if raw:
+                if not raw:
                     # X-Forwarded-For may be a comma-separated list; the leftmost
                     # entry is the original client (proxies append to the right).
                     client_ip = raw.split(",")[0].strip()
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
        from stampbot.main import app
    
        # Use TestClient as context manager to trigger lifespan events
        with TestClient(app) as client:
            # App should be running
>           response = client.get("/health")
                       ^^^^^^^^^^^^^^^^^^^^^

tests/test_main.py:20: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.main.LoggingMiddleware object at 0x7ff6bb023a10>
scope = {'app': <fastapi.applications.FastAPI object at 0x7ff6bb0dfb60>, 'client': ('testclient', 50000), 'extensions': {'http... b'*/*'), (b'accept-encoding', b'gzip, deflate'), (b'connection', b'keep-alive'), (b'user-agent', b'testclient')], ...}
receive = <function _TestClientTransport.handle_request.<locals>.receive at 0x7ff6bae82a30>
send = <function ServerErrorMiddleware.__call__.<locals>._send at 0x7ff6bae82fb0>

    async def __call__(self, scope: Any, receive: Any, send: Any) -> None:
        """Process an ASGI event, binding client IP to the structlog context.
    
        For HTTP scopes the middleware clears any inherited structlog context,
        extracts the real client IP from the configured forwarding header (or
        the direct connection address as a fallback), and binds it so that
        every log record emitted during the request includes ``client_ip``.
    
        Non-HTTP scopes (lifespan, WebSocket) are passed through unchanged.
    
        Args:
            scope: ASGI connection scope.
            receive: ASGI receive callable.
            send: ASGI send callable.
        """
        if scope["type"] == "http":
            structlog.contextvars.clear_contextvars()
    
            client_ip: str | None = None
            client_ip_header: str = settings.get("client_ip_header", "X-Forwarded-For")
    
            if client_ip_header:
                raw = Request(scope).headers.get(client_ip_header)
                if not raw:
                    # X-Forwarded-For may be a comma-separated list; the leftmost
                    # entry is the original client (proxies append to the right).
>                   client_ip = raw.split(",")[0].strip()
                                ^^^^^^^^^
E                   AttributeError: 'NoneType' object has no attribute 'split'

stampbot/main.py:202: AttributeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:19:19.199934Z [info     ] OpenTelemetry disabled         [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info
2026-06-29T04:19:19.321927Z [info     ] Starting stampbot on 0.0.0.0:8000 [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info extra={'host': '0.0.0.0', 'port': 8000, 'log_level': 'INFO'}
2026-06-29T04:19:19.322253Z [info     ] GitHub App credentials configured successfully [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
2026-06-29T04:19:19.323507Z [info     ] Shutting down stampbot         [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - AttributeError: 'NoneType' object has no attribute 'split'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.52s
operator: core/AddNot, occurrence: 6, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -201,7 +201,7 @@
                     # entry is the original client (proxies append to the right).
                     client_ip = raw.split(",")[0].strip()
 
-            if not client_ip and scope.get("client"):
+            if not not client_ip and scope.get("client"):
                 client_ip = scope["client"][0]
 
             if client_ip:
........................................................................ [ 30%]
..............................................F
=================================== FAILURES ===================================
______________ test_logging_middleware_respects_configured_header ______________

    def test_logging_middleware_respects_configured_header():
        """Test that logging_middleware uses the configured client_ip_header setting."""
        from unittest.mock import patch
    
        import structlog.contextvars
    
        from stampbot.main import app
    
        with patch("stampbot.main.settings") as mock_settings:
            mock_settings.get = lambda key, default=None: (
                "X-Real-IP" if key == "client_ip_header" else default
            )
    
            client = TestClient(app)
            captured: dict[str, str | None] = {}
    
            original_bind = structlog.contextvars.bind_contextvars
    
            def capturing_bind(**kw: object) -> None:
                captured.update({k: str(v) for k, v in kw.items()})
                original_bind(**kw)
    
            with patch("stampbot.main.structlog.contextvars.bind_contextvars", capturing_bind):
                client.get("/health", headers={"X-Real-IP": "198.51.100.7"})
    
>           assert captured.get("client_ip") == "198.51.100.7"
E           AssertionError: assert 'testclient' == '198.51.100.7'
E             
E             - 198.51.100.7
E             + testclient

tests/test_main.py:338: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:46:02.059052Z [info     ] HTTP Request: GET http://testserver/health "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/health "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_logging_middleware_respects_configured_header - AssertionError: assert 'testclient' == '198.51.100.7'
  
  - 198.51.100.7
  + testclient
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 118 passed, 3 deselected, 1 warning in 2.39s
operator: core/AddNot, occurrence: 7, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -204,7 +204,7 @@
             if not client_ip and scope.get("client"):
                 client_ip = scope["client"][0]
 
-            if client_ip:
+            if not client_ip:
                 structlog.contextvars.bind_contextvars(client_ip=client_ip)
 
         await self.app(scope, receive, send)
........................................................................ [ 30%]
..............................................F
=================================== FAILURES ===================================
______________ test_logging_middleware_respects_configured_header ______________

    def test_logging_middleware_respects_configured_header():
        """Test that logging_middleware uses the configured client_ip_header setting."""
        from unittest.mock import patch
    
        import structlog.contextvars
    
        from stampbot.main import app
    
        with patch("stampbot.main.settings") as mock_settings:
            mock_settings.get = lambda key, default=None: (
                "X-Real-IP" if key == "client_ip_header" else default
            )
    
            client = TestClient(app)
            captured: dict[str, str | None] = {}
    
            original_bind = structlog.contextvars.bind_contextvars
    
            def capturing_bind(**kw: object) -> None:
                captured.update({k: str(v) for k, v in kw.items()})
                original_bind(**kw)
    
            with patch("stampbot.main.structlog.contextvars.bind_contextvars", capturing_bind):
                client.get("/health", headers={"X-Real-IP": "198.51.100.7"})
    
>           assert captured.get("client_ip") == "198.51.100.7"
E           AssertionError: assert None == '198.51.100.7'
E            +  where None = <built-in method get of dict object at 0x7fc424b29040>('client_ip')
E            +    where <built-in method get of dict object at 0x7fc424b29040> = {}.get

tests/test_main.py:338: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:49:34.601776Z [info     ] HTTP Request: GET http://testserver/health "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/health "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_logging_middleware_respects_configured_header - AssertionError: assert None == '198.51.100.7'
 +  where None = <built-in method get of dict object at 0x7fc424b29040>('client_ip')
 +    where <built-in method get of dict object at 0x7fc424b29040> = {}.get
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 118 passed, 3 deselected, 1 warning in 2.38s
operator: core/AddNot, occurrence: 8, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -220,7 +220,7 @@
     Returns:
         Redirect to /setup if unconfigured, otherwise JSON status response.
     """
-    if not is_configured() and settings.setup_enabled:
+    if not not is_configured() and settings.setup_enabled:
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7f07fc92f9d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
        response = test_client.get("/")
        assert response.status_code == 200
>       data = response.json()
               ^^^^^^^^^^^^^^^

tests/test_main.py:46: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_models.py:832: in json
    return jsonlib.loads(self.content, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/json/__init__.py:352: in loads
    return _default_decoder.decode(s)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/json/decoder.py:345: in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <json.decoder.JSONDecoder object at 0x7f0804092f90>
s = '\n            <!DOCTYPE html>\n            <html>\n            <head><title>Stampbot - Already Configured</title>\n  ...pbot is ready to receive webhooks.</p>\n                </div>\n            </body>\n            </html>\n            '
idx = 13

    def raw_decode(self, s, idx=0):
        """Decode a JSON document from ``s`` (a ``str`` beginning with
        a JSON document) and return a 2-tuple of the Python
        representation and the index in ``s`` where the document ended.
    
        This can be used to decode a JSON document from a string that may
        have extraneous data at the end.
    
        """
        try:
            obj, end = self.scan_once(s, idx)
        except StopIteration as err:
>           raise JSONDecodeError("Expecting value", s, err.value) from None
E           json.decoder.JSONDecodeError: Expecting value: line 2 column 13 (char 13)

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/json/decoder.py:363: JSONDecodeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:46:54.843362Z [info     ] HTTP Request: GET http://testserver/ "HTTP/1.1 307 Temporary Redirect" [httpx]
2026-06-29T04:46:54.845674Z [info     ] HTTP Request: GET http://testserver/setup "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/ "HTTP/1.1 307 Temporary Redirect"
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - json.decoder.JSONDecodeError: Expecting value: line 2 column 13 (char 13)
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.36s
operator: core/AddNot, occurrence: 9, definition_name: ready
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -270,7 +270,7 @@
     checks = {"configured": configured, "setup_enabled": setup_enabled}
     is_ready = configured or setup_enabled
     return JSONResponse(
-        status_code=200 if is_ready else 503,
+        status_code=200 if not is_ready else 503,
         content={"status": "ready" if is_ready else "not ready", "checks": checks},
     )
 
........................................................................ [ 30%]
...............................F
=================================== FAILURES ===================================
________________________ test_ready_endpoint_configured ________________________

test_client = <starlette.testclient.TestClient object at 0x7f7f560af820>

    def test_ready_endpoint_configured(test_client: TestClient):
        """Test readiness endpoint returns 200 when the app is configured."""
        with patch("stampbot.main.is_configured", return_value=True):
            response = test_client.get("/ready")
>       assert response.status_code == 200
E       assert 503 == 200
E        +  where 503 = <Response [503 Service Unavailable]>.status_code

tests/test_main.py:63: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:51:04.344075Z [info     ] HTTP Request: GET http://testserver/ready "HTTP/1.1 503 Service Unavailable" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/ready "HTTP/1.1 503 Service Unavailable"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_ready_endpoint_configured - assert 503 == 200
 +  where 503 = <Response [503 Service Unavailable]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 103 passed, 3 deselected, 1 warning in 2.33s
operator: core/AddNot, occurrence: 10, definition_name: ready
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -271,7 +271,7 @@
     is_ready = configured or setup_enabled
     return JSONResponse(
         status_code=200 if is_ready else 503,
-        content={"status": "ready" if is_ready else "not ready", "checks": checks},
+        content={"status": "ready" if not is_ready else "not ready", "checks": checks},
     )
 
 
........................................................................ [ 30%]
...............................F
=================================== FAILURES ===================================
________________________ test_ready_endpoint_configured ________________________

test_client = <starlette.testclient.TestClient object at 0x7f81ecb9b820>

    def test_ready_endpoint_configured(test_client: TestClient):
        """Test readiness endpoint returns 200 when the app is configured."""
        with patch("stampbot.main.is_configured", return_value=True):
            response = test_client.get("/ready")
        assert response.status_code == 200
        data = response.json()
>       assert data["status"] == "ready"
E       AssertionError: assert 'not ready' == 'ready'
E         
E         - ready
E         + not ready

tests/test_main.py:65: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:44:28.378138Z [info     ] HTTP Request: GET http://testserver/ready "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/ready "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_ready_endpoint_configured - AssertionError: assert 'not ready' == 'ready'
  
  - ready
  + not ready
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 103 passed, 3 deselected, 1 warning in 2.34s
operator: core/AddNot, occurrence: 11, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -309,7 +309,7 @@
             413 if body too large, 503 if not configured, 500 on internal error.
     """
     # Check if app is configured
-    if not is_configured():
+    if not not is_configured():
         raise HTTPException(
             status_code=503,
             detail="Stampbot not configured. Visit /setup to complete setup.",
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f2a5e492250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 503 == 401
E        +  where 503 = <Response [503 Service Unavailable]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:26:26.196107Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 503 Service Unavailable" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 503 Service Unavailable"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 503 == 401
 +  where 503 = <Response [503 Service Unavailable]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.35s
operator: core/AddNot, occurrence: 12, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -315,7 +315,7 @@
             detail="Stampbot not configured. Visit /setup to complete setup.",
         )
 
-    if not x_github_event:
+    if not not x_github_event:
         errors_total.labels(error_type="missing_event").inc()
         raise HTTPException(status_code=400, detail="Missing X-GitHub-Event header")
 
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f145536e250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 400 == 401
E        +  where 400 = <Response [400 Bad Request]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:41:03.339932Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 400 Bad Request" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 400 Bad Request"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 400 == 401
 +  where 400 = <Response [400 Bad Request]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.35s
operator: core/AddNot, occurrence: 13, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -321,7 +321,7 @@
 
     # Check content length before reading body to prevent memory exhaustion
     content_length = request.headers.get("content-length")
-    if content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
+    if not content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
.........................................F
=================================== FAILURES ===================================
____________________ test_webhook_content_length_too_large _____________________

test_client = <starlette.testclient.TestClient object at 0x7f273aa8b350>

    def test_webhook_content_length_too_large(test_client: TestClient):
        """Test webhook rejects requests with Content-Length exceeding limit."""
        response = test_client.post(
            "/webhook",
            content=b"x",  # Small actual body
            headers={
                "Content-Type": "application/json",
                "Content-Length": "20000000",  # 20MB - exceeds 10MB limit
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=fake",
            },
        )
>       assert response.status_code == 413
E       assert 401 == 413
E        +  where 401 = <Response [401 Unauthorized]>.status_code

tests/test_main.py:235: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:37:51.516393Z [warning  ] Invalid webhook signature      [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=warning client_ip=testclient
2026-06-29T04:37:51.517201Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized" [httpx]
------------------------------ Captured log call -------------------------------
WARNING  stampbot.main:main.py:340 {'event': 'Invalid webhook signature', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'warning', 'timestamp': '2026-06-29T04:37:51.516393Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_content_length_too_large - assert 401 == 413
 +  where 401 = <Response [401 Unauthorized]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 113 passed, 3 deselected, 1 warning in 2.37s
operator: core/AddNot, occurrence: 14, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -329,7 +329,7 @@
     body = await request.body()
 
     # Double-check actual body size (in case content-length was missing/incorrect)
-    if len(body) > MAX_WEBHOOK_BODY_SIZE:
+    if not len(body) > MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f934e862250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:42:49.791725Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.37s
operator: core/AddNot, occurrence: 15, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -334,7 +334,7 @@
         raise HTTPException(status_code=413, detail="Request body too large")
 
     # Verify signature
-    if not webhook_handler.verify_signature(body, x_hub_signature_256):
+    if not not webhook_handler.verify_signature(body, x_hub_signature_256):
         webhook_signature_validations_total.labels(result="invalid").inc()
         errors_total.labels(error_type="signature_invalid").inc()
         logger.warning("Invalid webhook signature")
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7fc8a0e76250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 200 == 401
E        +  where 200 = <Response [200 OK]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:52:59.883638Z [info     ] Received ping event            [stampbot.webhook_handler] _logger=<_FixedFindCallerLogger stampbot.webhook_handler (INFO)> _name=info client_ip=testclient extra={'event_type': 'ping', 'action': ''}
2026-06-29T04:52:59.884581Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     stampbot.webhook_handler:webhook_handler.py:108 {'extra': {'event_type': 'ping', 'action': ''}, 'event': 'Received ping event', 'client_ip': 'testclient', 'logger': 'stampbot.webhook_handler', 'level': 'info', 'timestamp': '2026-06-29T04:52:59.883638Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 200 == 401
 +  where 200 = <Response [200 OK]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.38s
operator: core/AddNot, occurrence: 16, definition_name: setup_page
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -386,7 +386,7 @@
     Raises:
         HTTPException: If setup is disabled (403).
     """
-    if not settings.setup_enabled:
+    if not not settings.setup_enabled:
         raise HTTPException(status_code=403, detail="Setup not allowed in this environment")
 
     if is_configured():
........................................................................ [ 30%]
........................................................................ [ 60%]
.F
=================================== FAILURES ===================================
_______ TestSetupEndpointsConfigured.test_setup_shows_already_configured _______

self = <tests.test_setup_endpoints.TestSetupEndpointsConfigured object at 0x7fd79b538050>
test_client = <starlette.testclient.TestClient object at 0x7fd797573130>

    def test_setup_shows_already_configured(self, test_client):
        """Test /setup shows already configured message."""
        response = test_client.get("/setup")
    
>       assert response.status_code == 200
E       assert 403 == 200
E        +  where 403 = <Response [403 Forbidden]>.status_code

tests/test_setup_endpoints.py:68: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:22:07.677351Z [info     ] HTTP Request: GET http://testserver/setup "HTTP/1.1 403 Forbidden" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup "HTTP/1.1 403 Forbidden"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupEndpointsConfigured::test_setup_shows_already_configured - assert 403 == 200
 +  where 403 = <Response [403 Forbidden]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 145 passed, 3 deselected, 1 warning in 2.58s
operator: core/AddNot, occurrence: 17, definition_name: setup_page
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -389,7 +389,7 @@
     if not settings.setup_enabled:
         raise HTTPException(status_code=403, detail="Setup not allowed in this environment")
 
-    if is_configured():
+    if not is_configured():
         return HTMLResponse(
             content="""
             <!DOCTYPE html>
........................................................................ [ 30%]
........................................................................ [ 60%]
.F
=================================== FAILURES ===================================
_______ TestSetupEndpointsConfigured.test_setup_shows_already_configured _______

self = <tests.test_setup_endpoints.TestSetupEndpointsConfigured object at 0x7f8803aec050>
test_client = <starlette.testclient.TestClient object at 0x7f87ffa4b130>

    def test_setup_shows_already_configured(self, test_client):
        """Test /setup shows already configured message."""
>       response = test_client.get("/setup")
                   ^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_setup_endpoints.py:66: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:437: in setup_page
    manifest = create_manifest(redirect_url, webhook_url=webhook_url)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/manifest.py:85: in create_manifest
    _validate_url(redirect_url, "redirect_url")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

url = 'http://testserver/setup/callback', name = 'redirect_url'

    def _validate_url(url: str, name: str) -> None:
        """Validate that a URL is well-formed and uses HTTPS (or localhost).
    
        Args:
            url: URL to validate
            name: Name of the URL parameter for error messages
    
        Raises:
            ValueError: If URL is invalid or doesn't use HTTPS
        """
        parsed = urlparse(url)
    
        if not parsed.scheme or not parsed.netloc:
            raise ValueError(f"Invalid {name}: must be a complete URL")
    
        # Allow http only for localhost (development)
        if parsed.scheme == "http":
            if parsed.hostname not in ("localhost", "127.0.0.1", "::1"):
>               raise ValueError(f"Invalid {name}: must use HTTPS (HTTP only allowed for localhost)")
E               ValueError: Invalid redirect_url: must use HTTPS (HTTP only allowed for localhost)

stampbot/manifest.py:36: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupEndpointsConfigured::test_setup_shows_already_configured - ValueError: Invalid redirect_url: must use HTTPS (HTTP only allowed for localhost)
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 145 passed, 3 deselected, 1 warning in 2.91s
operator: core/AddNot, occurrence: 18, definition_name: setup_page
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -420,7 +420,7 @@
     # 2. Proxy headers (X-Forwarded-Proto + Host/X-Forwarded-Host)
     # 3. Request base URL (fallback)
     configured_base_url = settings.get("base_url", "")
-    if configured_base_url:
+    if not configured_base_url:
         base_url = configured_base_url.rstrip("/")
     else:
         # Check for proxy headers from ingress/load balancer
........................................................................ [ 30%]
........................................................................ [ 60%]
....F
=================================== FAILURES ===================================
___ TestSetupEndpointsUnconfigured.test_setup_shows_wizard_when_unconfigured ___

self = <tests.test_setup_endpoints.TestSetupEndpointsUnconfigured object at 0x7f51d11542d0>

    def test_setup_shows_wizard_when_unconfigured(self):
        """Test /setup shows setup wizard page when not configured."""
        with (
            patch("stampbot.main.is_configured", return_value=False),
            patch("stampbot.main.settings") as mock_settings,
        ):
            mock_settings.setup_enabled = True
            mock_settings.get.return_value = ""  # No base_url override
    
            from fastapi.testclient import TestClient
    
            from stampbot.main import app
    
            client = TestClient(app, raise_server_exceptions=False)
            response = client.get("/setup", headers={"Host": "localhost:8000"})
    
>           assert response.status_code == 200
E           assert 500 == 200
E            +  where 500 = <Response [500 Internal Server Error]>.status_code

tests/test_setup_endpoints.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:26:24.101746Z [info     ] HTTP Request: GET http://testserver/setup "HTTP/1.1 500 Internal Server Error" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup "HTTP/1.1 500 Internal Server Error"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupEndpointsUnconfigured::test_setup_shows_wizard_when_unconfigured - assert 500 == 200
 +  where 500 = <Response [500 Internal Server Error]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 148 passed, 3 deselected, 1 warning in 2.56s
operator: core/AddNot, occurrence: 19, definition_name: setup_page
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -427,7 +427,7 @@
         # Cloud Run sends X-Forwarded-Proto but uses standard Host header
         forwarded_proto = request.headers.get("X-Forwarded-Proto", "")
         forwarded_host = request.headers.get("X-Forwarded-Host", request.headers.get("Host", ""))
-        if forwarded_proto and forwarded_host:
+        if not forwarded_proto and forwarded_host:
             base_url = f"{forwarded_proto}://{forwarded_host}"
         else:
             base_url = str(request.base_url).rstrip("/")
........................................................................ [ 30%]
........................................................................ [ 60%]
....F
=================================== FAILURES ===================================
___ TestSetupEndpointsUnconfigured.test_setup_shows_wizard_when_unconfigured ___

self = <tests.test_setup_endpoints.TestSetupEndpointsUnconfigured object at 0x7f46205f82d0>

    def test_setup_shows_wizard_when_unconfigured(self):
        """Test /setup shows setup wizard page when not configured."""
        with (
            patch("stampbot.main.is_configured", return_value=False),
            patch("stampbot.main.settings") as mock_settings,
        ):
            mock_settings.setup_enabled = True
            mock_settings.get.return_value = ""  # No base_url override
    
            from fastapi.testclient import TestClient
    
            from stampbot.main import app
    
            client = TestClient(app, raise_server_exceptions=False)
            response = client.get("/setup", headers={"Host": "localhost:8000"})
    
>           assert response.status_code == 200
E           assert 500 == 200
E            +  where 500 = <Response [500 Internal Server Error]>.status_code

tests/test_setup_endpoints.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:21:38.119064Z [info     ] HTTP Request: GET http://testserver/setup "HTTP/1.1 500 Internal Server Error" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup "HTTP/1.1 500 Internal Server Error"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupEndpointsUnconfigured::test_setup_shows_wizard_when_unconfigured - assert 500 == 200
 +  where 500 = <Response [500 Internal Server Error]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 148 passed, 3 deselected, 1 warning in 2.58s
operator: core/AddNot, occurrence: 20, definition_name: setup_callback
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -508,7 +508,7 @@
     Raises:
         HTTPException: If setup disabled (403) or code exchange fails (500).
     """
-    if not settings.setup_enabled:
+    if not not settings.setup_enabled:
         raise HTTPException(status_code=403, detail="Setup not allowed")
 
     try:
........................................................................ [ 30%]
........................................................................ [ 60%]
........F
=================================== FAILURES ===================================
________________ TestSetupCallback.test_callback_exchanges_code ________________

self = <tests.test_setup_endpoints.TestSetupCallback object at 0x7fd34a258410>
test_client = <starlette.testclient.TestClient object at 0x7fd346281260>

    def test_callback_exchanges_code(self, test_client):
        """Test callback exchanges code for credentials."""
        mock_credentials = {
            "id": 12345,
            "pem": "-----BEGIN RSA PRIVATE KEY-----\ntest\n-----END RSA PRIVATE KEY-----",
            "webhook_secret": "test-secret",
            "slug": "test-stampbot",
            "name": "Test Stampbot",
        }
    
        with patch(
            "stampbot.main.exchange_code_for_credentials",
            new_callable=AsyncMock,
            return_value=mock_credentials,
        ):
            response = test_client.get("/setup/callback?code=test-code")
    
>           assert response.status_code == 200
E           assert 403 == 200
E            +  where 403 = <Response [403 Forbidden]>.status_code

tests/test_setup_endpoints.py:230: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:19:55.887595Z [info     ] HTTP Request: GET http://testserver/setup/callback?code=test-code "HTTP/1.1 403 Forbidden" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup/callback?code=test-code "HTTP/1.1 403 Forbidden"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupCallback::test_callback_exchanges_code - assert 403 == 200
 +  where 403 = <Response [403 Forbidden]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 152 passed, 3 deselected, 1 warning in 2.58s
operator: core/AddNot, occurrence: 21, definition_name: setup_status
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -617,6 +617,6 @@
     return {
         "configured": is_configured(),
         "setup_enabled": settings.setup_enabled,
-        "app_id": settings.app_id if is_configured() else None,
+        "app_id": settings.app_id if not is_configured() else None,
     }
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceAndWithOr, occurrence: 0, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -201,7 +201,7 @@
                     # entry is the original client (proxies append to the right).
                     client_ip = raw.split(",")[0].strip()
 
-            if not client_ip and scope.get("client"):
+            if not client_ip or scope.get("client"):
                 client_ip = scope["client"][0]
 
             if client_ip:
........................................................................ [ 30%]
..............................................F
=================================== FAILURES ===================================
______________ test_logging_middleware_respects_configured_header ______________

    def test_logging_middleware_respects_configured_header():
        """Test that logging_middleware uses the configured client_ip_header setting."""
        from unittest.mock import patch
    
        import structlog.contextvars
    
        from stampbot.main import app
    
        with patch("stampbot.main.settings") as mock_settings:
            mock_settings.get = lambda key, default=None: (
                "X-Real-IP" if key == "client_ip_header" else default
            )
    
            client = TestClient(app)
            captured: dict[str, str | None] = {}
    
            original_bind = structlog.contextvars.bind_contextvars
    
            def capturing_bind(**kw: object) -> None:
                captured.update({k: str(v) for k, v in kw.items()})
                original_bind(**kw)
    
            with patch("stampbot.main.structlog.contextvars.bind_contextvars", capturing_bind):
                client.get("/health", headers={"X-Real-IP": "198.51.100.7"})
    
>           assert captured.get("client_ip") == "198.51.100.7"
E           AssertionError: assert 'testclient' == '198.51.100.7'
E             
E             - 198.51.100.7
E             + testclient

tests/test_main.py:338: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:30:46.468490Z [info     ] HTTP Request: GET http://testserver/health "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/health "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_logging_middleware_respects_configured_header - AssertionError: assert 'testclient' == '198.51.100.7'
  
  - 198.51.100.7
  + testclient
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 118 passed, 3 deselected, 1 warning in 2.38s
operator: core/ReplaceAndWithOr, occurrence: 1, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -220,7 +220,7 @@
     Returns:
         Redirect to /setup if unconfigured, otherwise JSON status response.
     """
-    if not is_configured() and settings.setup_enabled:
+    if not is_configured() or settings.setup_enabled:
         return RedirectResponse(url="/setup", status_code=307)
 
     return Response(
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7ff3c20279d0>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
        response = test_client.get("/")
        assert response.status_code == 200
>       data = response.json()
               ^^^^^^^^^^^^^^^

tests/test_main.py:46: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_models.py:832: in json
    return jsonlib.loads(self.content, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/json/__init__.py:352: in loads
    return _default_decoder.decode(s)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/json/decoder.py:345: in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <json.decoder.JSONDecoder object at 0x7ff3c978ef90>
s = '\n            <!DOCTYPE html>\n            <html>\n            <head><title>Stampbot - Already Configured</title>\n  ...pbot is ready to receive webhooks.</p>\n                </div>\n            </body>\n            </html>\n            '
idx = 13

    def raw_decode(self, s, idx=0):
        """Decode a JSON document from ``s`` (a ``str`` beginning with
        a JSON document) and return a 2-tuple of the Python
        representation and the index in ``s`` where the document ended.
    
        This can be used to decode a JSON document from a string that may
        have extraneous data at the end.
    
        """
        try:
            obj, end = self.scan_once(s, idx)
        except StopIteration as err:
>           raise JSONDecodeError("Expecting value", s, err.value) from None
E           json.decoder.JSONDecodeError: Expecting value: line 2 column 13 (char 13)

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/json/decoder.py:363: JSONDecodeError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:34:21.964828Z [info     ] HTTP Request: GET http://testserver/ "HTTP/1.1 307 Temporary Redirect" [httpx]
2026-06-29T04:34:21.967072Z [info     ] HTTP Request: GET http://testserver/setup "HTTP/1.1 200 OK" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/ "HTTP/1.1 307 Temporary Redirect"
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup "HTTP/1.1 200 OK"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - json.decoder.JSONDecodeError: Expecting value: line 2 column 13 (char 13)
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.35s
operator: core/ReplaceAndWithOr, occurrence: 2, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -321,7 +321,7 @@
 
     # Check content length before reading body to prevent memory exhaustion
     content_length = request.headers.get("content-length")
-    if content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
+    if content_length or int(content_length) > MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
         raise HTTPException(status_code=413, detail="Request body too large")
 
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f330245e250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 413 == 401
E        +  where 413 = <Response [413 Request Entity Too Large]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:49:45.540049Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 413 Request Entity Too Large"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 413 == 401
 +  where 413 = <Response [413 Request Entity Too Large]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.33s
operator: core/ReplaceAndWithOr, occurrence: 3, definition_name: setup_page
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -427,7 +427,7 @@
         # Cloud Run sends X-Forwarded-Proto but uses standard Host header
         forwarded_proto = request.headers.get("X-Forwarded-Proto", "")
         forwarded_host = request.headers.get("X-Forwarded-Host", request.headers.get("Host", ""))
-        if forwarded_proto and forwarded_host:
+        if forwarded_proto or forwarded_host:
             base_url = f"{forwarded_proto}://{forwarded_host}"
         else:
             base_url = str(request.base_url).rstrip("/")
........................................................................ [ 30%]
........................................................................ [ 60%]
....F
=================================== FAILURES ===================================
___ TestSetupEndpointsUnconfigured.test_setup_shows_wizard_when_unconfigured ___

self = <tests.test_setup_endpoints.TestSetupEndpointsUnconfigured object at 0x7f0d491502d0>

    def test_setup_shows_wizard_when_unconfigured(self):
        """Test /setup shows setup wizard page when not configured."""
        with (
            patch("stampbot.main.is_configured", return_value=False),
            patch("stampbot.main.settings") as mock_settings,
        ):
            mock_settings.setup_enabled = True
            mock_settings.get.return_value = ""  # No base_url override
    
            from fastapi.testclient import TestClient
    
            from stampbot.main import app
    
            client = TestClient(app, raise_server_exceptions=False)
            response = client.get("/setup", headers={"Host": "localhost:8000"})
    
>           assert response.status_code == 200
E           assert 500 == 200
E            +  where 500 = <Response [500 Internal Server Error]>.status_code

tests/test_setup_endpoints.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:55:24.884518Z [info     ] HTTP Request: GET http://testserver/setup "HTTP/1.1 500 Internal Server Error" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup "HTTP/1.1 500 Internal Server Error"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupEndpointsUnconfigured::test_setup_shows_wizard_when_unconfigured - assert 500 == 200
 +  where 500 = <Response [500 Internal Server Error]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 148 passed, 3 deselected, 1 warning in 2.58s
operator: core/ReplaceOrWithAnd, occurrence: 0, definition_name: ready
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -268,7 +268,7 @@
     configured = is_configured()
     setup_enabled = bool(settings.setup_enabled)
     checks = {"configured": configured, "setup_enabled": setup_enabled}
-    is_ready = configured or setup_enabled
+    is_ready = configured and setup_enabled
     return JSONResponse(
         status_code=200 if is_ready else 503,
         content={"status": "ready" if is_ready else "not ready", "checks": checks},
........................................................................ [ 30%]
................................F
=================================== FAILURES ===================================
________________ test_ready_endpoint_unconfigured_setup_enabled ________________

test_client = <starlette.testclient.TestClient object at 0x7f4829e855b0>

    def test_ready_endpoint_unconfigured_setup_enabled(test_client: TestClient):
        """Test readiness is 200 in setup mode so /setup stays reachable.
    
        An unconfigured pod with setup mode on must stay in the Service endpoints,
        otherwise the operator can never reach /setup to configure it.
        """
        with (
            patch("stampbot.main.is_configured", return_value=False),
            patch("stampbot.main.settings") as mock_settings,
        ):
            mock_settings.setup_enabled = True
            response = test_client.get("/ready")
>       assert response.status_code == 200
E       assert 503 == 200
E        +  where 503 = <Response [503 Service Unavailable]>.status_code

tests/test_main.py:81: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:08:47.259883Z [info     ] HTTP Request: GET http://testserver/ready "HTTP/1.1 503 Service Unavailable" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/ready "HTTP/1.1 503 Service Unavailable"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_ready_endpoint_unconfigured_setup_enabled - assert 503 == 200
 +  where 503 = <Response [503 Service Unavailable]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 104 passed, 3 deselected, 1 warning in 2.34s
operator: core/ReplaceOrWithAnd, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -356,7 +356,7 @@
         result = await webhook_handler.handle_event(x_github_event, payload)
         duration = time.time() - start_time
 
-        webhook_processing_duration_seconds.labels(event_type=x_github_event or "unknown").observe(
+        webhook_processing_duration_seconds.labels(event_type=x_github_event and "unknown").observe(
             duration
         )
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ExceptionReplacer, occurrence: 0, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -345,7 +345,7 @@
     # Parse JSON payload
     try:
         payload = await request.json()
-    except Exception as e:
+    except CosmicRayTestingException as e:
         errors_total.labels(error_type="payload_invalid").inc()
         logger.error("Failed to parse webhook payload: %s", e)
         raise HTTPException(status_code=400, detail="Invalid JSON payload") from None
........................................................................ [ 30%]
.......................................F
=================================== FAILURES ===================================
__________________________ test_webhook_invalid_json ___________________________

request = <starlette.requests.Request object at 0x7f427c6c35f0>
x_github_event = 'ping'
x_hub_signature_256 = 'sha256=dc481541cb8394ab16852fc7c7cbce720b045e7456801ae3998a45f260ad2915'

    @app.post("/webhook")
    async def webhook(
        request: Request,
        x_github_event: str = Header(None, alias="X-GitHub-Event"),
        x_hub_signature_256: str = Header(None, alias="X-Hub-Signature-256"),
    ) -> dict[str, Any]:
        """GitHub webhook endpoint.
    
        Args:
            request: FastAPI request.
            x_github_event: GitHub event type.
            x_hub_signature_256: Webhook signature.
    
        Returns:
            Response dictionary with status and message.
    
        Raises:
            HTTPException: 400 if event header or JSON invalid, 401 if signature invalid,
                413 if body too large, 503 if not configured, 500 on internal error.
        """
        # Check if app is configured
        if not is_configured():
            raise HTTPException(
                status_code=503,
                detail="Stampbot not configured. Visit /setup to complete setup.",
            )
    
        if not x_github_event:
            errors_total.labels(error_type="missing_event").inc()
            raise HTTPException(status_code=400, detail="Missing X-GitHub-Event header")
    
        # Check content length before reading body to prevent memory exhaustion
        content_length = request.headers.get("content-length")
        if content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
            errors_total.labels(error_type="payload_too_large").inc()
            raise HTTPException(status_code=413, detail="Request body too large")
    
        # Get raw body for signature verification
        body = await request.body()
    
        # Double-check actual body size (in case content-length was missing/incorrect)
        if len(body) > MAX_WEBHOOK_BODY_SIZE:
            errors_total.labels(error_type="payload_too_large").inc()
            raise HTTPException(status_code=413, detail="Request body too large")
    
        # Verify signature
        if not webhook_handler.verify_signature(body, x_hub_signature_256):
            webhook_signature_validations_total.labels(result="invalid").inc()
            errors_total.labels(error_type="signature_invalid").inc()
            logger.warning("Invalid webhook signature")
            raise HTTPException(status_code=401, detail="Invalid signature")
    
        webhook_signature_validations_total.labels(result="valid").inc()
    
        # Parse JSON payload
        try:
>           payload = await request.json()
                      ^^^^^^^^^^^^^^^^^^^^

stampbot/main.py:347: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/requests.py:265: in json
    self._json = json.loads(body)
                 ^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/json/__init__.py:352: in loads
    return _default_decoder.decode(s)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/json/decoder.py:345: in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <json.decoder.JSONDecoder object at 0x7f4283d8ef90>, s = 'not valid json'
idx = 0

    def raw_decode(self, s, idx=0):
        """Decode a JSON document from ``s`` (a ``str`` beginning with
        a JSON document) and return a 2-tuple of the Python
        representation and the index in ``s`` where the document ended.
    
        This can be used to decode a JSON document from a string that may
        have extraneous data at the end.
    
        """
        try:
            obj, end = self.scan_once(s, idx)
        except StopIteration as err:
>           raise JSONDecodeError("Expecting value", s, err.value) from None
E           json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/json/decoder.py:363: JSONDecodeError

The above exception was the direct cause of the following exception:

test_client = <starlette.testclient.TestClient object at 0x7f427c6669c0>

    def test_webhook_invalid_json(test_client: TestClient):
        """Test webhook rejects invalid JSON payload."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        # Create a valid signature for invalid JSON
        body = b"not valid json"
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
>       response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )

tests/test_main.py:178: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

request = <starlette.requests.Request object at 0x7f427c6c35f0>
x_github_event = 'ping'
x_hub_signature_256 = 'sha256=dc481541cb8394ab16852fc7c7cbce720b045e7456801ae3998a45f260ad2915'

    @app.post("/webhook")
    async def webhook(
        request: Request,
        x_github_event: str = Header(None, alias="X-GitHub-Event"),
        x_hub_signature_256: str = Header(None, alias="X-Hub-Signature-256"),
    ) -> dict[str, Any]:
        """GitHub webhook endpoint.
    
        Args:
            request: FastAPI request.
            x_github_event: GitHub event type.
            x_hub_signature_256: Webhook signature.
    
        Returns:
            Response dictionary with status and message.
    
        Raises:
            HTTPException: 400 if event header or JSON invalid, 401 if signature invalid,
                413 if body too large, 503 if not configured, 500 on internal error.
        """
        # Check if app is configured
        if not is_configured():
            raise HTTPException(
                status_code=503,
                detail="Stampbot not configured. Visit /setup to complete setup.",
            )
    
        if not x_github_event:
            errors_total.labels(error_type="missing_event").inc()
            raise HTTPException(status_code=400, detail="Missing X-GitHub-Event header")
    
        # Check content length before reading body to prevent memory exhaustion
        content_length = request.headers.get("content-length")
        if content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
            errors_total.labels(error_type="payload_too_large").inc()
            raise HTTPException(status_code=413, detail="Request body too large")
    
        # Get raw body for signature verification
        body = await request.body()
    
        # Double-check actual body size (in case content-length was missing/incorrect)
        if len(body) > MAX_WEBHOOK_BODY_SIZE:
            errors_total.labels(error_type="payload_too_large").inc()
            raise HTTPException(status_code=413, detail="Request body too large")
    
        # Verify signature
        if not webhook_handler.verify_signature(body, x_hub_signature_256):
            webhook_signature_validations_total.labels(result="invalid").inc()
            errors_total.labels(error_type="signature_invalid").inc()
            logger.warning("Invalid webhook signature")
            raise HTTPException(status_code=401, detail="Invalid signature")
    
        webhook_signature_validations_total.labels(result="valid").inc()
    
        # Parse JSON payload
        try:
            payload = await request.json()
>       except CosmicRayTestingException as e:
               ^^^^^^^^^^^^^^^^^^^^^^^^^
E       NameError: name 'CosmicRayTestingException' is not defined

stampbot/main.py:348: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_invalid_json - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 111 passed, 3 deselected, 1 warning in 2.70s
operator: core/ExceptionReplacer, occurrence: 1, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -361,7 +361,7 @@
         )
 
         return result
-    except Exception as e:
+    except CosmicRayTestingException as e:
         errors_total.labels(error_type="webhook_handler_error").inc()
         sanitized = _sanitize_error(e)
         logger.error("Error handling webhook event: %s", sanitized, extra={"error": sanitized})
........................................................................ [ 30%]
................................................F
=================================== FAILURES ===================================
________________________ test_webhook_handler_exception ________________________

request = <starlette.requests.Request object at 0x7f18fcaf6570>
x_github_event = 'ping'
x_hub_signature_256 = 'sha256=595bde46b32458346f405d2b0b88ade07c42ddd464fa4cb8df965915cfa558d2'

    @app.post("/webhook")
    async def webhook(
        request: Request,
        x_github_event: str = Header(None, alias="X-GitHub-Event"),
        x_hub_signature_256: str = Header(None, alias="X-Hub-Signature-256"),
    ) -> dict[str, Any]:
        """GitHub webhook endpoint.
    
        Args:
            request: FastAPI request.
            x_github_event: GitHub event type.
            x_hub_signature_256: Webhook signature.
    
        Returns:
            Response dictionary with status and message.
    
        Raises:
            HTTPException: 400 if event header or JSON invalid, 401 if signature invalid,
                413 if body too large, 503 if not configured, 500 on internal error.
        """
        # Check if app is configured
        if not is_configured():
            raise HTTPException(
                status_code=503,
                detail="Stampbot not configured. Visit /setup to complete setup.",
            )
    
        if not x_github_event:
            errors_total.labels(error_type="missing_event").inc()
            raise HTTPException(status_code=400, detail="Missing X-GitHub-Event header")
    
        # Check content length before reading body to prevent memory exhaustion
        content_length = request.headers.get("content-length")
        if content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
            errors_total.labels(error_type="payload_too_large").inc()
            raise HTTPException(status_code=413, detail="Request body too large")
    
        # Get raw body for signature verification
        body = await request.body()
    
        # Double-check actual body size (in case content-length was missing/incorrect)
        if len(body) > MAX_WEBHOOK_BODY_SIZE:
            errors_total.labels(error_type="payload_too_large").inc()
            raise HTTPException(status_code=413, detail="Request body too large")
    
        # Verify signature
        if not webhook_handler.verify_signature(body, x_hub_signature_256):
            webhook_signature_validations_total.labels(result="invalid").inc()
            errors_total.labels(error_type="signature_invalid").inc()
            logger.warning("Invalid webhook signature")
            raise HTTPException(status_code=401, detail="Invalid signature")
    
        webhook_signature_validations_total.labels(result="valid").inc()
    
        # Parse JSON payload
        try:
            payload = await request.json()
        except Exception as e:
            errors_total.labels(error_type="payload_invalid").inc()
            logger.error("Failed to parse webhook payload: %s", e)
            raise HTTPException(status_code=400, detail="Invalid JSON payload") from None
    
        # Handle event with timing
        try:
            start_time = time.time()
>           result = await webhook_handler.handle_event(x_github_event, payload)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/main.py:356: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <AsyncMock name='handle_event' id='139745296466000'>
args = ('ping', {'zen': 'test'}), kwargs = {}
_call = call('ping', {'zen': 'test'}), effect = Exception('Unexpected error')

    async def _execute_mock_call(self, /, *args, **kwargs):
        # This is nearly just like super(), except for special handling
        # of coroutines
    
        _call = _Call((args, kwargs), two=True)
        self.await_count += 1
        self.await_args = _call
        self.await_args_list.append(_call)
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: Unexpected error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:2333: Exception

The above exception was the direct cause of the following exception:

test_client = <starlette.testclient.TestClient object at 0x7f18fca76250>

    def test_webhook_handler_exception(test_client: TestClient):
        """Test webhook returns 500 when handler raises exception."""
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "test"}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        with patch("stampbot.main.webhook_handler.handle_event") as mock_handle:
            mock_handle.side_effect = Exception("Unexpected error")
    
>           response = test_client.post(
                "/webhook",
                content=body,
                headers={
                    "Content-Type": "application/json",
                    "X-GitHub-Event": "ping",
                    "X-Hub-Signature-256": signature,
                },
            )

tests/test_main.py:392: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:555: in post
    return super().post(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1144: in post
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:454: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

request = <starlette.requests.Request object at 0x7f18fcaf6570>
x_github_event = 'ping'
x_hub_signature_256 = 'sha256=595bde46b32458346f405d2b0b88ade07c42ddd464fa4cb8df965915cfa558d2'

    @app.post("/webhook")
    async def webhook(
        request: Request,
        x_github_event: str = Header(None, alias="X-GitHub-Event"),
        x_hub_signature_256: str = Header(None, alias="X-Hub-Signature-256"),
    ) -> dict[str, Any]:
        """GitHub webhook endpoint.
    
        Args:
            request: FastAPI request.
            x_github_event: GitHub event type.
            x_hub_signature_256: Webhook signature.
    
        Returns:
            Response dictionary with status and message.
    
        Raises:
            HTTPException: 400 if event header or JSON invalid, 401 if signature invalid,
                413 if body too large, 503 if not configured, 500 on internal error.
        """
        # Check if app is configured
        if not is_configured():
            raise HTTPException(
                status_code=503,
                detail="Stampbot not configured. Visit /setup to complete setup.",
            )
    
        if not x_github_event:
            errors_total.labels(error_type="missing_event").inc()
            raise HTTPException(status_code=400, detail="Missing X-GitHub-Event header")
    
        # Check content length before reading body to prevent memory exhaustion
        content_length = request.headers.get("content-length")
        if content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
            errors_total.labels(error_type="payload_too_large").inc()
            raise HTTPException(status_code=413, detail="Request body too large")
    
        # Get raw body for signature verification
        body = await request.body()
    
        # Double-check actual body size (in case content-length was missing/incorrect)
        if len(body) > MAX_WEBHOOK_BODY_SIZE:
            errors_total.labels(error_type="payload_too_large").inc()
            raise HTTPException(status_code=413, detail="Request body too large")
    
        # Verify signature
        if not webhook_handler.verify_signature(body, x_hub_signature_256):
            webhook_signature_validations_total.labels(result="invalid").inc()
            errors_total.labels(error_type="signature_invalid").inc()
            logger.warning("Invalid webhook signature")
            raise HTTPException(status_code=401, detail="Invalid signature")
    
        webhook_signature_validations_total.labels(result="valid").inc()
    
        # Parse JSON payload
        try:
            payload = await request.json()
        except Exception as e:
            errors_total.labels(error_type="payload_invalid").inc()
            logger.error("Failed to parse webhook payload: %s", e)
            raise HTTPException(status_code=400, detail="Invalid JSON payload") from None
    
        # Handle event with timing
        try:
            start_time = time.time()
            result = await webhook_handler.handle_event(x_github_event, payload)
            duration = time.time() - start_time
    
            webhook_processing_duration_seconds.labels(event_type=x_github_event or "unknown").observe(
                duration
            )
    
            return result
>       except CosmicRayTestingException as e:
               ^^^^^^^^^^^^^^^^^^^^^^^^^
E       NameError: name 'CosmicRayTestingException' is not defined

stampbot/main.py:364: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_handler_exception - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 120 passed, 3 deselected, 1 warning in 2.75s
operator: core/ExceptionReplacer, occurrence: 2, definition_name: setup_callback
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -513,7 +513,7 @@
 
     try:
         credentials = await exchange_code_for_credentials(code)
-    except Exception as e:
+    except CosmicRayTestingException as e:
         logger.error("Failed to exchange code for credentials: %s", _sanitize_error(e))
         raise HTTPException(status_code=500, detail="Failed to complete setup") from None
 
........................................................................ [ 30%]
........................................................................ [ 60%]
..........F
=================================== FAILURES ===================================
____________ TestSetupCallback.test_callback_handles_exchange_error ____________

request = <starlette.requests.Request object at 0x7fe000cd19c0>
code = 'bad-code'

    @app.get("/setup/callback")
    async def setup_callback(request: Request, code: str) -> Response:
        """Handle callback from GitHub after app creation.
    
        Args:
            request: FastAPI request.
            code: Temporary code from GitHub to exchange for credentials.
    
        Returns:
            HTML page with credentials and setup instructions.
    
        Raises:
            HTTPException: If setup disabled (403) or code exchange fails (500).
        """
        if not settings.setup_enabled:
            raise HTTPException(status_code=403, detail="Setup not allowed")
    
        try:
>           credentials = await exchange_code_for_credentials(code)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/main.py:515: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <AsyncMock name='exchange_code_for_credentials' id='140600075722368'>
args = ('bad-code',), kwargs = {}, _call = call('bad-code')
effect = Exception('API error')

    async def _execute_mock_call(self, /, *args, **kwargs):
        # This is nearly just like super(), except for special handling
        # of coroutines
    
        _call = _Call((args, kwargs), two=True)
        self.await_count += 1
        self.await_args = _call
        self.await_args_list.append(_call)
    
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
>               raise effect
E               Exception: API error

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:2333: Exception

The above exception was the direct cause of the following exception:

self = <tests.test_setup_endpoints.TestSetupCallback object at 0x7fe005648050>
test_client = <starlette.testclient.TestClient object at 0x7fe0017748d0>

    def test_callback_handles_exchange_error(self, test_client):
        """Test callback handles exchange error gracefully."""
        with patch(
            "stampbot.main.exchange_code_for_credentials",
            new_callable=AsyncMock,
            side_effect=Exception("API error"),
        ):
>           response = test_client.get("/setup/callback?code=bad-code")
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_setup_endpoints.py:264: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
stampbot/main.py:210: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:193: in __call__
    response = await self.dispatch_func(request, call_next)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stampbot/main.py:125: in metrics_middleware
    response = await call_next(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:168: in call_next
    raise app_exc from app_exc.__cause__ or app_exc.__context__
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/base.py:144: in coro
    await self.app(scope, receive_or_disconnect, send_no_error)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/exceptions.py:63: in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/middleware/asyncexitstack.py:18: in __call__
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:660: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:680: in app
    await route.handle(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/routing.py:276: in handle
    await self.app(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:134: in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:53: in wrapped_app
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/_exception_handler.py:42: in wrapped_app
    await app(scope, receive, sender)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:120: in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:674: in app
    raw_response = await run_endpoint_function(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/routing.py:328: in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

request = <starlette.requests.Request object at 0x7fe000cd19c0>
code = 'bad-code'

    @app.get("/setup/callback")
    async def setup_callback(request: Request, code: str) -> Response:
        """Handle callback from GitHub after app creation.
    
        Args:
            request: FastAPI request.
            code: Temporary code from GitHub to exchange for credentials.
    
        Returns:
            HTML page with credentials and setup instructions.
    
        Raises:
            HTTPException: If setup disabled (403) or code exchange fails (500).
        """
        if not settings.setup_enabled:
            raise HTTPException(status_code=403, detail="Setup not allowed")
    
        try:
            credentials = await exchange_code_for_credentials(code)
>       except CosmicRayTestingException as e:
               ^^^^^^^^^^^^^^^^^^^^^^^^^
E       NameError: name 'CosmicRayTestingException' is not defined

stampbot/main.py:516: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupCallback::test_callback_handles_exchange_error - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 154 passed, 3 deselected, 1 warning in 2.98s
operator: core/NumberReplacer, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -52,7 +52,7 @@
 APP_VERSION = "0.1.0"
 
 # Security limits
-MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
+MAX_WEBHOOK_BODY_SIZE = 1025 * 1024  # 1MB - GitHub webhooks are typically much smaller
 
 
 @asynccontextmanager
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/NumberReplacer, occurrence: 1, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -52,7 +52,7 @@
 APP_VERSION = "0.1.0"
 
 # Security limits
-MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
+MAX_WEBHOOK_BODY_SIZE = 1023 * 1024  # 1MB - GitHub webhooks are typically much smaller
 
 
 @asynccontextmanager
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/NumberReplacer, occurrence: 2, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -52,7 +52,7 @@
 APP_VERSION = "0.1.0"
 
 # Security limits
-MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
+MAX_WEBHOOK_BODY_SIZE = 1024 * 1025  # 1MB - GitHub webhooks are typically much smaller
 
 
 @asynccontextmanager
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/NumberReplacer, occurrence: 3, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -52,7 +52,7 @@
 APP_VERSION = "0.1.0"
 
 # Security limits
-MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
+MAX_WEBHOOK_BODY_SIZE = 1024 * 1023  # 1MB - GitHub webhooks are typically much smaller
 
 
 @asynccontextmanager
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.27s
operator: core/NumberReplacer, occurrence: 4, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -199,7 +199,7 @@
                 if raw:
                     # X-Forwarded-For may be a comma-separated list; the leftmost
                     # entry is the original client (proxies append to the right).
-                    client_ip = raw.split(",")[0].strip()
+                    client_ip = raw.split(",")[ 1].strip()
 
             if not client_ip and scope.get("client"):
                 client_ip = scope["client"][0]
........................................................................ [ 30%]
..............................................F
=================================== FAILURES ===================================
______________ test_logging_middleware_respects_configured_header ______________

    def test_logging_middleware_respects_configured_header():
        """Test that logging_middleware uses the configured client_ip_header setting."""
        from unittest.mock import patch
    
        import structlog.contextvars
    
        from stampbot.main import app
    
        with patch("stampbot.main.settings") as mock_settings:
            mock_settings.get = lambda key, default=None: (
                "X-Real-IP" if key == "client_ip_header" else default
            )
    
            client = TestClient(app)
            captured: dict[str, str | None] = {}
    
            original_bind = structlog.contextvars.bind_contextvars
    
            def capturing_bind(**kw: object) -> None:
                captured.update({k: str(v) for k, v in kw.items()})
                original_bind(**kw)
    
            with patch("stampbot.main.structlog.contextvars.bind_contextvars", capturing_bind):
>               client.get("/health", headers={"X-Real-IP": "198.51.100.7"})

tests/test_main.py:336: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:482: in get
    return super().get(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1053: in get
    return self.request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:454: in request
    return super().request(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:825: in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:914: in send
    response = self._send_handling_auth(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:942: in _send_handling_auth
    response = self._send_handling_redirects(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:979: in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/httpx/_client.py:1014: in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:356: in handle_request
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/testclient.py:353: in handle_request
    portal.call(self.app, scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:338: in call
    return cast(T_Retval, self.start_task_soon(func, *args).result())
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:447: in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/concurrent/futures/_base.py:396: in __get_result
    raise self._exception
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/anyio/from_thread.py:263: in _call_func
    retval = await retval_or_awaitable
             ^^^^^^^^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/applications.py:1159: in __call__
    await super().__call__(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/applications.py:90: in __call__
    await self.middleware_stack(scope, receive, send)
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:186: in __call__
    raise exc
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/starlette/middleware/errors.py:164: in __call__
    await self.app(scope, receive, _send)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <stampbot.main.LoggingMiddleware object at 0x7fb69c833a10>
scope = {'app': <fastapi.applications.FastAPI object at 0x7fb69c8efb60>, 'client': ('testclient', 50000), 'extensions': {'http...gzip, deflate'), (b'connection', b'keep-alive'), (b'user-agent', b'testclient'), (b'x-real-ip', b'198.51.100.7')], ...}
receive = <function _TestClientTransport.handle_request.<locals>.receive at 0x7fb69c514720>
send = <function ServerErrorMiddleware.__call__.<locals>._send at 0x7fb69c515590>

    async def __call__(self, scope: Any, receive: Any, send: Any) -> None:
        """Process an ASGI event, binding client IP to the structlog context.
    
        For HTTP scopes the middleware clears any inherited structlog context,
        extracts the real client IP from the configured forwarding header (or
        the direct connection address as a fallback), and binds it so that
        every log record emitted during the request includes ``client_ip``.
    
        Non-HTTP scopes (lifespan, WebSocket) are passed through unchanged.
    
        Args:
            scope: ASGI connection scope.
            receive: ASGI receive callable.
            send: ASGI send callable.
        """
        if scope["type"] == "http":
            structlog.contextvars.clear_contextvars()
    
            client_ip: str | None = None
            client_ip_header: str = settings.get("client_ip_header", "X-Forwarded-For")
    
            if client_ip_header:
                raw = Request(scope).headers.get(client_ip_header)
                if raw:
                    # X-Forwarded-For may be a comma-separated list; the leftmost
                    # entry is the original client (proxies append to the right).
>                   client_ip = raw.split(",")[ 1].strip()
                                ^^^^^^^^^^^^^^^^^^
E                   IndexError: list index out of range

stampbot/main.py:202: IndexError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_logging_middleware_respects_configured_header - IndexError: list index out of range
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 118 passed, 3 deselected, 1 warning in 2.58s
operator: core/NumberReplacer, occurrence: 5, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -199,7 +199,7 @@
                 if raw:
                     # X-Forwarded-For may be a comma-separated list; the leftmost
                     # entry is the original client (proxies append to the right).
-                    client_ip = raw.split(",")[0].strip()
+                    client_ip = raw.split(",")[ -1].strip()
 
             if not client_ip and scope.get("client"):
                 client_ip = scope["client"][0]
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/NumberReplacer, occurrence: 6, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -202,7 +202,7 @@
                     client_ip = raw.split(",")[0].strip()
 
             if not client_ip and scope.get("client"):
-                client_ip = scope["client"][0]
+                client_ip = scope["client"][ 1]
 
             if client_ip:
                 structlog.contextvars.bind_contextvars(client_ip=client_ip)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/NumberReplacer, occurrence: 7, definition_name: __call__
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -202,7 +202,7 @@
                     client_ip = raw.split(",")[0].strip()
 
             if not client_ip and scope.get("client"):
-                client_ip = scope["client"][0]
+                client_ip = scope["client"][ -1]
 
             if client_ip:
                 structlog.contextvars.bind_contextvars(client_ip=client_ip)
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/NumberReplacer, occurrence: 8, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -221,7 +221,7 @@
         Redirect to /setup if unconfigured, otherwise JSON status response.
     """
     if not is_configured() and settings.setup_enabled:
-        return RedirectResponse(url="/setup", status_code=307)
+        return RedirectResponse(url="/setup", status_code= 308)
 
     return Response(
         content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
........................................................................ [ 30%]
........................................................................ [ 60%]
...F
=================================== FAILURES ===================================
_ TestSetupEndpointsUnconfigured.test_root_redirects_to_setup_when_unconfigured _

self = <tests.test_setup_endpoints.TestSetupEndpointsUnconfigured object at 0x7fd40c078190>

    def test_root_redirects_to_setup_when_unconfigured(self):
        """Test root redirects to /setup when not configured."""
        with (
            patch("stampbot.main.is_configured", return_value=False),
            patch("stampbot.main.settings") as mock_settings,
        ):
            mock_settings.setup_enabled = True
            mock_settings.app_name = "stampbot"
            mock_settings.host = "0.0.0.0"
            mock_settings.port = 8000
            mock_settings.log_level = "INFO"
    
            from fastapi.testclient import TestClient
    
            from stampbot.main import app
    
            client = TestClient(app, raise_server_exceptions=False)
            response = client.get("/", follow_redirects=False)
    
>           assert response.status_code == 307
E           assert 308 == 307
E            +  where 308 = <Response [308 Permanent Redirect]>.status_code

tests/test_setup_endpoints.py:102: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:28:39.438564Z [info     ] HTTP Request: GET http://testserver/ "HTTP/1.1 308 Permanent Redirect" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/ "HTTP/1.1 308 Permanent Redirect"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupEndpointsUnconfigured::test_root_redirects_to_setup_when_unconfigured - assert 308 == 307
 +  where 308 = <Response [308 Permanent Redirect]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 147 passed, 3 deselected, 1 warning in 2.57s
operator: core/NumberReplacer, occurrence: 9, definition_name: root
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -221,7 +221,7 @@
         Redirect to /setup if unconfigured, otherwise JSON status response.
     """
     if not is_configured() and settings.setup_enabled:
-        return RedirectResponse(url="/setup", status_code=307)
+        return RedirectResponse(url="/setup", status_code= 306)
 
     return Response(
         content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
........................................................................ [ 30%]
........................................................................ [ 60%]
...F
=================================== FAILURES ===================================
_ TestSetupEndpointsUnconfigured.test_root_redirects_to_setup_when_unconfigured _

self = <tests.test_setup_endpoints.TestSetupEndpointsUnconfigured object at 0x7f8f5185c190>

    def test_root_redirects_to_setup_when_unconfigured(self):
        """Test root redirects to /setup when not configured."""
        with (
            patch("stampbot.main.is_configured", return_value=False),
            patch("stampbot.main.settings") as mock_settings,
        ):
            mock_settings.setup_enabled = True
            mock_settings.app_name = "stampbot"
            mock_settings.host = "0.0.0.0"
            mock_settings.port = 8000
            mock_settings.log_level = "INFO"
    
            from fastapi.testclient import TestClient
    
            from stampbot.main import app
    
            client = TestClient(app, raise_server_exceptions=False)
            response = client.get("/", follow_redirects=False)
    
>           assert response.status_code == 307
E           assert 306 == 307
E            +  where 306 = <Response [306 ]>.status_code

tests/test_setup_endpoints.py:102: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:32:42.948889Z [info     ] HTTP Request: GET http://testserver/ "HTTP/1.1 306 " [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/ "HTTP/1.1 306 "
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupEndpointsUnconfigured::test_root_redirects_to_setup_when_unconfigured - assert 306 == 307
 +  where 306 = <Response [306 ]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 147 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 10, definition_name: ready
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -270,7 +270,7 @@
     checks = {"configured": configured, "setup_enabled": setup_enabled}
     is_ready = configured or setup_enabled
     return JSONResponse(
-        status_code=200 if is_ready else 503,
+        status_code= 201 if is_ready else 503,
         content={"status": "ready" if is_ready else "not ready", "checks": checks},
     )
 
........................................................................ [ 30%]
...............................F
=================================== FAILURES ===================================
________________________ test_ready_endpoint_configured ________________________

test_client = <starlette.testclient.TestClient object at 0x7fc217fb7820>

    def test_ready_endpoint_configured(test_client: TestClient):
        """Test readiness endpoint returns 200 when the app is configured."""
        with patch("stampbot.main.is_configured", return_value=True):
            response = test_client.get("/ready")
>       assert response.status_code == 200
E       assert 201 == 200
E        +  where 201 = <Response [201 Created]>.status_code

tests/test_main.py:63: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:18:59.490092Z [info     ] HTTP Request: GET http://testserver/ready "HTTP/1.1 201 Created" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/ready "HTTP/1.1 201 Created"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_ready_endpoint_configured - assert 201 == 200
 +  where 201 = <Response [201 Created]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 103 passed, 3 deselected, 1 warning in 2.34s
operator: core/NumberReplacer, occurrence: 11, definition_name: ready
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -270,7 +270,7 @@
     checks = {"configured": configured, "setup_enabled": setup_enabled}
     is_ready = configured or setup_enabled
     return JSONResponse(
-        status_code=200 if is_ready else 503,
+        status_code= 199 if is_ready else 503,
         content={"status": "ready" if is_ready else "not ready", "checks": checks},
     )
 
........................................................................ [ 30%]
...............................F
=================================== FAILURES ===================================
________________________ test_ready_endpoint_configured ________________________

test_client = <starlette.testclient.TestClient object at 0x7fb2cf68f820>

    def test_ready_endpoint_configured(test_client: TestClient):
        """Test readiness endpoint returns 200 when the app is configured."""
        with patch("stampbot.main.is_configured", return_value=True):
            response = test_client.get("/ready")
>       assert response.status_code == 200
E       assert 199 == 200
E        +  where 199 = <Response [199 ]>.status_code

tests/test_main.py:63: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:44:58.106981Z [info     ] HTTP Request: GET http://testserver/ready "HTTP/1.1 199 " [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/ready "HTTP/1.1 199 "
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_ready_endpoint_configured - assert 199 == 200
 +  where 199 = <Response [199 ]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 103 passed, 3 deselected, 1 warning in 2.32s
operator: core/NumberReplacer, occurrence: 12, definition_name: ready
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -270,7 +270,7 @@
     checks = {"configured": configured, "setup_enabled": setup_enabled}
     is_ready = configured or setup_enabled
     return JSONResponse(
-        status_code=200 if is_ready else 503,
+        status_code=200 if is_ready else 504,
         content={"status": "ready" if is_ready else "not ready", "checks": checks},
     )
 
........................................................................ [ 30%]
.................................F
=================================== FAILURES ===================================
_______________ test_ready_endpoint_unconfigured_setup_disabled ________________

test_client = <starlette.testclient.TestClient object at 0x7f9852e7c8d0>

    def test_ready_endpoint_unconfigured_setup_disabled(test_client: TestClient):
        """Test readiness is 503 only when unconfigured and setup is disabled."""
        with (
            patch("stampbot.main.is_configured", return_value=False),
            patch("stampbot.main.settings") as mock_settings,
        ):
            mock_settings.setup_enabled = False
            response = test_client.get("/ready")
>       assert response.status_code == 503
E       assert 504 == 503
E        +  where 504 = <Response [504 Gateway Timeout]>.status_code

tests/test_main.py:95: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:20:20.734591Z [info     ] HTTP Request: GET http://testserver/ready "HTTP/1.1 504 Gateway Timeout" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/ready "HTTP/1.1 504 Gateway Timeout"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_ready_endpoint_unconfigured_setup_disabled - assert 504 == 503
 +  where 504 = <Response [504 Gateway Timeout]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 105 passed, 3 deselected, 1 warning in 2.32s
operator: core/NumberReplacer, occurrence: 13, definition_name: ready
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -270,7 +270,7 @@
     checks = {"configured": configured, "setup_enabled": setup_enabled}
     is_ready = configured or setup_enabled
     return JSONResponse(
-        status_code=200 if is_ready else 503,
+        status_code=200 if is_ready else 502,
         content={"status": "ready" if is_ready else "not ready", "checks": checks},
     )
 
........................................................................ [ 30%]
.................................F
=================================== FAILURES ===================================
_______________ test_ready_endpoint_unconfigured_setup_disabled ________________

test_client = <starlette.testclient.TestClient object at 0x7f24fdc608d0>

    def test_ready_endpoint_unconfigured_setup_disabled(test_client: TestClient):
        """Test readiness is 503 only when unconfigured and setup is disabled."""
        with (
            patch("stampbot.main.is_configured", return_value=False),
            patch("stampbot.main.settings") as mock_settings,
        ):
            mock_settings.setup_enabled = False
            response = test_client.get("/ready")
>       assert response.status_code == 503
E       assert 502 == 503
E        +  where 502 = <Response [502 Bad Gateway]>.status_code

tests/test_main.py:95: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:46:23.414901Z [info     ] HTTP Request: GET http://testserver/ready "HTTP/1.1 502 Bad Gateway" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/ready "HTTP/1.1 502 Bad Gateway"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_ready_endpoint_unconfigured_setup_disabled - assert 502 == 503
 +  where 502 = <Response [502 Bad Gateway]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 105 passed, 3 deselected, 1 warning in 2.33s
operator: core/NumberReplacer, occurrence: 14, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -311,7 +311,7 @@
     # Check if app is configured
     if not is_configured():
         raise HTTPException(
-            status_code=503,
+            status_code= 504,
             detail="Stampbot not configured. Visit /setup to complete setup.",
         )
 
........................................................................ [ 30%]
........................................................................ [ 60%]
.......F
=================================== FAILURES ===================================
__ TestSetupEndpointsUnconfigured.test_webhook_returns_503_when_unconfigured ___

self = <tests.test_setup_endpoints.TestSetupEndpointsUnconfigured object at 0x7efd2773c290>

    def test_webhook_returns_503_when_unconfigured(self):
        """Test webhook returns 503 when not configured."""
        with (
            patch("stampbot.main.is_configured", return_value=False),
            patch("stampbot.main.settings") as mock_settings,
        ):
            mock_settings.setup_enabled = True
    
            from fastapi.testclient import TestClient
    
            from stampbot.main import app
    
            client = TestClient(app, raise_server_exceptions=False)
            response = client.post("/webhook", json={})
    
>           assert response.status_code == 503
E           assert 504 == 503
E            +  where 504 = <Response [504 Gateway Timeout]>.status_code

tests/test_setup_endpoints.py:206: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:32:14.011200Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 504 Gateway Timeout" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 504 Gateway Timeout"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupEndpointsUnconfigured::test_webhook_returns_503_when_unconfigured - assert 504 == 503
 +  where 504 = <Response [504 Gateway Timeout]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 151 passed, 3 deselected, 1 warning in 2.56s
operator: core/NumberReplacer, occurrence: 15, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -311,7 +311,7 @@
     # Check if app is configured
     if not is_configured():
         raise HTTPException(
-            status_code=503,
+            status_code= 502,
             detail="Stampbot not configured. Visit /setup to complete setup.",
         )
 
........................................................................ [ 30%]
........................................................................ [ 60%]
.......F
=================================== FAILURES ===================================
__ TestSetupEndpointsUnconfigured.test_webhook_returns_503_when_unconfigured ___

self = <tests.test_setup_endpoints.TestSetupEndpointsUnconfigured object at 0x7f9f12c58290>

    def test_webhook_returns_503_when_unconfigured(self):
        """Test webhook returns 503 when not configured."""
        with (
            patch("stampbot.main.is_configured", return_value=False),
            patch("stampbot.main.settings") as mock_settings,
        ):
            mock_settings.setup_enabled = True
    
            from fastapi.testclient import TestClient
    
            from stampbot.main import app
    
            client = TestClient(app, raise_server_exceptions=False)
            response = client.post("/webhook", json={})
    
>           assert response.status_code == 503
E           assert 502 == 503
E            +  where 502 = <Response [502 Bad Gateway]>.status_code

tests/test_setup_endpoints.py:206: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:19:04.305145Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 502 Bad Gateway" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 502 Bad Gateway"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupEndpointsUnconfigured::test_webhook_returns_503_when_unconfigured - assert 502 == 503
 +  where 502 = <Response [502 Bad Gateway]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 151 passed, 3 deselected, 1 warning in 2.59s
operator: core/NumberReplacer, occurrence: 16, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -317,7 +317,7 @@
 
     if not x_github_event:
         errors_total.labels(error_type="missing_event").inc()
-        raise HTTPException(status_code=400, detail="Missing X-GitHub-Event header")
+        raise HTTPException(status_code= 401, detail="Missing X-GitHub-Event header")
 
     # Check content length before reading body to prevent memory exhaustion
     content_length = request.headers.get("content-length")
........................................................................ [ 30%]
.....................................F
=================================== FAILURES ===================================
______________________ test_webhook_missing_event_header _______________________

test_client = <starlette.testclient.TestClient object at 0x7fba5988e140>

    def test_webhook_missing_event_header(test_client: TestClient):
        """Test webhook rejects requests without X-GitHub-Event header."""
        response = test_client.post(
            "/webhook",
            json={"zen": "test"},
            headers={"X-Hub-Signature-256": "sha256=invalid"},
        )
>       assert response.status_code == 400
E       assert 401 == 400
E        +  where 401 = <Response [401 Unauthorized]>.status_code

tests/test_main.py:142: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:56:32.957441Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_missing_event_header - assert 401 == 400
 +  where 401 = <Response [401 Unauthorized]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 109 passed, 3 deselected, 1 warning in 2.42s
operator: core/NumberReplacer, occurrence: 17, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -317,7 +317,7 @@
 
     if not x_github_event:
         errors_total.labels(error_type="missing_event").inc()
-        raise HTTPException(status_code=400, detail="Missing X-GitHub-Event header")
+        raise HTTPException(status_code= 399, detail="Missing X-GitHub-Event header")
 
     # Check content length before reading body to prevent memory exhaustion
     content_length = request.headers.get("content-length")
........................................................................ [ 30%]
.....................................F
=================================== FAILURES ===================================
______________________ test_webhook_missing_event_header _______________________

test_client = <starlette.testclient.TestClient object at 0x7f263a47a140>

    def test_webhook_missing_event_header(test_client: TestClient):
        """Test webhook rejects requests without X-GitHub-Event header."""
        response = test_client.post(
            "/webhook",
            json={"zen": "test"},
            headers={"X-Hub-Signature-256": "sha256=invalid"},
        )
>       assert response.status_code == 400
E       assert 399 == 400
E        +  where 399 = <Response [399 ]>.status_code

tests/test_main.py:142: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:11:47.221955Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 399 " [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 399 "
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_missing_event_header - assert 399 == 400
 +  where 399 = <Response [399 ]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 109 passed, 3 deselected, 1 warning in 2.37s
operator: core/NumberReplacer, occurrence: 18, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -323,7 +323,7 @@
     content_length = request.headers.get("content-length")
     if content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
-        raise HTTPException(status_code=413, detail="Request body too large")
+        raise HTTPException(status_code= 414, detail="Request body too large")
 
     # Get raw body for signature verification
     body = await request.body()
........................................................................ [ 30%]
.........................................F
=================================== FAILURES ===================================
____________________ test_webhook_content_length_too_large _____________________

test_client = <starlette.testclient.TestClient object at 0x7f381600f350>

    def test_webhook_content_length_too_large(test_client: TestClient):
        """Test webhook rejects requests with Content-Length exceeding limit."""
        response = test_client.post(
            "/webhook",
            content=b"x",  # Small actual body
            headers={
                "Content-Type": "application/json",
                "Content-Length": "20000000",  # 20MB - exceeds 10MB limit
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=fake",
            },
        )
>       assert response.status_code == 413
E       assert 414 == 413
E        +  where 414 = <Response [414 Request-URI Too Long]>.status_code

tests/test_main.py:235: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:44:07.967182Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 414 Request-URI Too Long" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 414 Request-URI Too Long"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_content_length_too_large - assert 414 == 413
 +  where 414 = <Response [414 Request-URI Too Long]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 113 passed, 3 deselected, 1 warning in 2.39s
operator: core/NumberReplacer, occurrence: 19, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -323,7 +323,7 @@
     content_length = request.headers.get("content-length")
     if content_length and int(content_length) > MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
-        raise HTTPException(status_code=413, detail="Request body too large")
+        raise HTTPException(status_code= 412, detail="Request body too large")
 
     # Get raw body for signature verification
     body = await request.body()
........................................................................ [ 30%]
.........................................F
=================================== FAILURES ===================================
____________________ test_webhook_content_length_too_large _____________________

test_client = <starlette.testclient.TestClient object at 0x7fd0eb28f350>

    def test_webhook_content_length_too_large(test_client: TestClient):
        """Test webhook rejects requests with Content-Length exceeding limit."""
        response = test_client.post(
            "/webhook",
            content=b"x",  # Small actual body
            headers={
                "Content-Type": "application/json",
                "Content-Length": "20000000",  # 20MB - exceeds 10MB limit
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=fake",
            },
        )
>       assert response.status_code == 413
E       assert 412 == 413
E        +  where 412 = <Response [412 Precondition Failed]>.status_code

tests/test_main.py:235: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:24:18.782461Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 412 Precondition Failed" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 412 Precondition Failed"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_content_length_too_large - assert 412 == 413
 +  where 412 = <Response [412 Precondition Failed]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 113 passed, 3 deselected, 1 warning in 2.38s
operator: core/NumberReplacer, occurrence: 20, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -331,7 +331,7 @@
     # Double-check actual body size (in case content-length was missing/incorrect)
     if len(body) > MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
-        raise HTTPException(status_code=413, detail="Request body too large")
+        raise HTTPException(status_code= 414, detail="Request body too large")
 
     # Verify signature
     if not webhook_handler.verify_signature(body, x_hub_signature_256):
........................................................................ [ 30%]
..........................................F
=================================== FAILURES ===================================
_________________________ test_webhook_body_too_large __________________________

test_client = <starlette.testclient.TestClient object at 0x7fbecce0b240>

    def test_webhook_body_too_large(test_client: TestClient):
        """Test webhook rejects requests where actual body exceeds limit.
    
        This tests the secondary body size check (lines 231-232) which catches
        cases where Content-Length header is missing or incorrect.
        """
        # Create a body larger than MAX_WEBHOOK_BODY_SIZE (10MB)
        large_body = b"x" * (10 * 1024 * 1024 + 1)  # 10MB + 1 byte
    
        # Set Content-Length to a small value to bypass the header check (line 222)
        # but the actual body size check (line 230) should still catch it
        response = test_client.post(
            "/webhook",
            content=large_body,
            headers={
                "Content-Type": "application/json",
                "Content-Length": "100",  # Lie about size to bypass first check
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=fake",
            },
        )
>       assert response.status_code == 413
E       assert 414 == 413
E        +  where 414 = <Response [414 Request-URI Too Long]>.status_code

tests/test_main.py:260: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:48:25.602374Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 414 Request-URI Too Long" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 414 Request-URI Too Long"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_body_too_large - assert 414 == 413
 +  where 414 = <Response [414 Request-URI Too Long]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 114 passed, 3 deselected, 1 warning in 2.38s
operator: core/NumberReplacer, occurrence: 21, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -331,7 +331,7 @@
     # Double-check actual body size (in case content-length was missing/incorrect)
     if len(body) > MAX_WEBHOOK_BODY_SIZE:
         errors_total.labels(error_type="payload_too_large").inc()
-        raise HTTPException(status_code=413, detail="Request body too large")
+        raise HTTPException(status_code= 412, detail="Request body too large")
 
     # Verify signature
     if not webhook_handler.verify_signature(body, x_hub_signature_256):
........................................................................ [ 30%]
..........................................F
=================================== FAILURES ===================================
_________________________ test_webhook_body_too_large __________________________

test_client = <starlette.testclient.TestClient object at 0x7fb5e8a63240>

    def test_webhook_body_too_large(test_client: TestClient):
        """Test webhook rejects requests where actual body exceeds limit.
    
        This tests the secondary body size check (lines 231-232) which catches
        cases where Content-Length header is missing or incorrect.
        """
        # Create a body larger than MAX_WEBHOOK_BODY_SIZE (10MB)
        large_body = b"x" * (10 * 1024 * 1024 + 1)  # 10MB + 1 byte
    
        # Set Content-Length to a small value to bypass the header check (line 222)
        # but the actual body size check (line 230) should still catch it
        response = test_client.post(
            "/webhook",
            content=large_body,
            headers={
                "Content-Type": "application/json",
                "Content-Length": "100",  # Lie about size to bypass first check
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=fake",
            },
        )
>       assert response.status_code == 413
E       assert 412 == 413
E        +  where 412 = <Response [412 Precondition Failed]>.status_code

tests/test_main.py:260: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:41:12.951531Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 412 Precondition Failed" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 412 Precondition Failed"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_body_too_large - assert 412 == 413
 +  where 412 = <Response [412 Precondition Failed]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 114 passed, 3 deselected, 1 warning in 2.36s
operator: core/NumberReplacer, occurrence: 22, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -338,7 +338,7 @@
         webhook_signature_validations_total.labels(result="invalid").inc()
         errors_total.labels(error_type="signature_invalid").inc()
         logger.warning("Invalid webhook signature")
-        raise HTTPException(status_code=401, detail="Invalid signature")
+        raise HTTPException(status_code= 402, detail="Invalid signature")
 
     webhook_signature_validations_total.labels(result="valid").inc()
 
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f0138466250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 402 == 401
E        +  where 402 = <Response [402 Payment Required]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:14:45.136884Z [warning  ] Invalid webhook signature      [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=warning client_ip=testclient
2026-06-29T05:14:45.137833Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 402 Payment Required" [httpx]
------------------------------ Captured log call -------------------------------
WARNING  stampbot.main:main.py:340 {'event': 'Invalid webhook signature', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'warning', 'timestamp': '2026-06-29T05:14:45.136884Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 402 Payment Required"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 402 == 401
 +  where 402 = <Response [402 Payment Required]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.36s
operator: core/NumberReplacer, occurrence: 23, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -338,7 +338,7 @@
         webhook_signature_validations_total.labels(result="invalid").inc()
         errors_total.labels(error_type="signature_invalid").inc()
         logger.warning("Invalid webhook signature")
-        raise HTTPException(status_code=401, detail="Invalid signature")
+        raise HTTPException(status_code= 400, detail="Invalid signature")
 
     webhook_signature_validations_total.labels(result="valid").inc()
 
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7f88b9576250>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 400 == 401
E        +  where 400 = <Response [400 Bad Request]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:10:29.646539Z [warning  ] Invalid webhook signature      [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=warning client_ip=testclient
2026-06-29T05:10:29.647493Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 400 Bad Request" [httpx]
------------------------------ Captured log call -------------------------------
WARNING  stampbot.main:main.py:340 {'event': 'Invalid webhook signature', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'warning', 'timestamp': '2026-06-29T05:10:29.646539Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 400 Bad Request"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 400 == 401
 +  where 400 = <Response [400 Bad Request]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.36s
operator: core/NumberReplacer, occurrence: 24, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -348,7 +348,7 @@
     except Exception as e:
         errors_total.labels(error_type="payload_invalid").inc()
         logger.error("Failed to parse webhook payload: %s", e)
-        raise HTTPException(status_code=400, detail="Invalid JSON payload") from None
+        raise HTTPException(status_code= 401, detail="Invalid JSON payload") from None
 
     # Handle event with timing
     try:
........................................................................ [ 30%]
.......................................F
=================================== FAILURES ===================================
__________________________ test_webhook_invalid_json ___________________________

test_client = <starlette.testclient.TestClient object at 0x7f40c0a769c0>

    def test_webhook_invalid_json(test_client: TestClient):
        """Test webhook rejects invalid JSON payload."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        # Create a valid signature for invalid JSON
        body = b"not valid json"
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
>       assert response.status_code == 400
E       assert 401 == 400
E        +  where 401 = <Response [401 Unauthorized]>.status_code

tests/test_main.py:187: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:01:09.066769Z [error    ] Failed to parse webhook payload: Expecting value: line 1 column 1 (char 0) [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=error client_ip=testclient
2026-06-29T05:01:09.067639Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized" [httpx]
------------------------------ Captured log call -------------------------------
ERROR    stampbot.main:main.py:350 {'event': 'Failed to parse webhook payload: Expecting value: line 1 column 1 (char 0)', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'error', 'timestamp': '2026-06-29T05:01:09.066769Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 401 Unauthorized"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_invalid_json - assert 401 == 400
 +  where 401 = <Response [401 Unauthorized]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 111 passed, 3 deselected, 1 warning in 2.38s
operator: core/NumberReplacer, occurrence: 25, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -348,7 +348,7 @@
     except Exception as e:
         errors_total.labels(error_type="payload_invalid").inc()
         logger.error("Failed to parse webhook payload: %s", e)
-        raise HTTPException(status_code=400, detail="Invalid JSON payload") from None
+        raise HTTPException(status_code= 399, detail="Invalid JSON payload") from None
 
     # Handle event with timing
     try:
........................................................................ [ 30%]
.......................................F
=================================== FAILURES ===================================
__________________________ test_webhook_invalid_json ___________________________

test_client = <starlette.testclient.TestClient object at 0x7fa26ef869c0>

    def test_webhook_invalid_json(test_client: TestClient):
        """Test webhook rejects invalid JSON payload."""
        import hashlib
        import hmac
    
        from stampbot.webhook_handler import webhook_handler
    
        # Create a valid signature for invalid JSON
        body = b"not valid json"
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        response = test_client.post(
            "/webhook",
            content=body,
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": signature,
            },
        )
>       assert response.status_code == 400
E       assert 399 == 400
E        +  where 399 = <Response [399 ]>.status_code

tests/test_main.py:187: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:43:27.997747Z [error    ] Failed to parse webhook payload: Expecting value: line 1 column 1 (char 0) [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=error client_ip=testclient
2026-06-29T05:43:27.998604Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 399 " [httpx]
------------------------------ Captured log call -------------------------------
ERROR    stampbot.main:main.py:350 {'event': 'Failed to parse webhook payload: Expecting value: line 1 column 1 (char 0)', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'error', 'timestamp': '2026-06-29T05:43:27.997747Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 399 "
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_invalid_json - assert 399 == 400
 +  where 399 = <Response [399 ]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 111 passed, 3 deselected, 1 warning in 2.38s
operator: core/NumberReplacer, occurrence: 26, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -365,7 +365,7 @@
         errors_total.labels(error_type="webhook_handler_error").inc()
         sanitized = _sanitize_error(e)
         logger.error("Error handling webhook event: %s", sanitized, extra={"error": sanitized})
-        raise HTTPException(status_code=500, detail="Internal server error") from None
+        raise HTTPException(status_code= 501, detail="Internal server error") from None
 
 
 # =============================================================================
........................................................................ [ 30%]
................................................F
=================================== FAILURES ===================================
________________________ test_webhook_handler_exception ________________________

test_client = <starlette.testclient.TestClient object at 0x7fe5f4b5e250>

    def test_webhook_handler_exception(test_client: TestClient):
        """Test webhook returns 500 when handler raises exception."""
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "test"}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        with patch("stampbot.main.webhook_handler.handle_event") as mock_handle:
            mock_handle.side_effect = Exception("Unexpected error")
    
            response = test_client.post(
                "/webhook",
                content=body,
                headers={
                    "Content-Type": "application/json",
                    "X-GitHub-Event": "ping",
                    "X-Hub-Signature-256": signature,
                },
            )
    
>       assert response.status_code == 500
E       assert 501 == 500
E        +  where 501 = <Response [501 Not Implemented]>.status_code

tests/test_main.py:402: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:38:06.305582Z [error    ] Error handling webhook event: Unexpected error [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=error client_ip=testclient extra={'error': 'Unexpected error'}
2026-06-29T04:38:06.306458Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 501 Not Implemented" [httpx]
------------------------------ Captured log call -------------------------------
ERROR    stampbot.main:main.py:367 {'extra': {'error': 'Unexpected error'}, 'event': 'Error handling webhook event: Unexpected error', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'error', 'timestamp': '2026-06-29T04:38:06.305582Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 501 Not Implemented"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_handler_exception - assert 501 == 500
 +  where 501 = <Response [501 Not Implemented]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 120 passed, 3 deselected, 1 warning in 2.38s
operator: core/NumberReplacer, occurrence: 27, definition_name: webhook
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -365,7 +365,7 @@
         errors_total.labels(error_type="webhook_handler_error").inc()
         sanitized = _sanitize_error(e)
         logger.error("Error handling webhook event: %s", sanitized, extra={"error": sanitized})
-        raise HTTPException(status_code=500, detail="Internal server error") from None
+        raise HTTPException(status_code= 499, detail="Internal server error") from None
 
 
 # =============================================================================
........................................................................ [ 30%]
................................................F
=================================== FAILURES ===================================
________________________ test_webhook_handler_exception ________________________

test_client = <starlette.testclient.TestClient object at 0x7fd76688a250>

    def test_webhook_handler_exception(test_client: TestClient):
        """Test webhook returns 500 when handler raises exception."""
        from stampbot.webhook_handler import webhook_handler
    
        body = json.dumps({"zen": "test"}).encode()
        signature = (
            "sha256="
            + hmac.new(
                webhook_handler.webhook_secret,
                body,
                hashlib.sha256,
            ).hexdigest()
        )
    
        with patch("stampbot.main.webhook_handler.handle_event") as mock_handle:
            mock_handle.side_effect = Exception("Unexpected error")
    
            response = test_client.post(
                "/webhook",
                content=body,
                headers={
                    "Content-Type": "application/json",
                    "X-GitHub-Event": "ping",
                    "X-Hub-Signature-256": signature,
                },
            )
    
>       assert response.status_code == 500
E       assert 499 == 500
E        +  where 499 = <Response [499 ]>.status_code

tests/test_main.py:402: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:30:26.915526Z [error    ] Error handling webhook event: Unexpected error [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=error client_ip=testclient extra={'error': 'Unexpected error'}
2026-06-29T05:30:26.916456Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 499 " [httpx]
------------------------------ Captured log call -------------------------------
ERROR    stampbot.main:main.py:367 {'extra': {'error': 'Unexpected error'}, 'event': 'Error handling webhook event: Unexpected error', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'error', 'timestamp': '2026-06-29T05:30:26.915526Z'}
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 499 "
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_webhook_handler_exception - assert 499 == 500
 +  where 499 = <Response [499 ]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 120 passed, 3 deselected, 1 warning in 2.40s
operator: core/NumberReplacer, occurrence: 28, definition_name: setup_page
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -387,7 +387,7 @@
         HTTPException: If setup is disabled (403).
     """
     if not settings.setup_enabled:
-        raise HTTPException(status_code=403, detail="Setup not allowed in this environment")
+        raise HTTPException(status_code= 404, detail="Setup not allowed in this environment")
 
     if is_configured():
         return HTMLResponse(
........................................................................ [ 30%]
........................................................................ [ 60%]
...........F
=================================== FAILURES ===================================
____________ TestSetupDisabled.test_setup_returns_403_when_disabled ____________

self = <tests.test_setup_endpoints.TestSetupDisabled object at 0x7f4645f3c690>

    def test_setup_returns_403_when_disabled(self):
        """Test /setup returns 403 when setup is disabled."""
        with (
            patch("stampbot.main.is_configured", return_value=False),
            patch("stampbot.main.settings") as mock_settings,
        ):
            mock_settings.setup_enabled = False
    
            from fastapi.testclient import TestClient
    
            from stampbot.main import app
    
            client = TestClient(app, raise_server_exceptions=False)
            response = client.get("/setup")
    
>           assert response.status_code == 403
E           assert 404 == 403
E            +  where 404 = <Response [404 Not Found]>.status_code

tests/test_setup_endpoints.py:287: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:30:11.249480Z [info     ] HTTP Request: GET http://testserver/setup "HTTP/1.1 404 Not Found" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup "HTTP/1.1 404 Not Found"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupDisabled::test_setup_returns_403_when_disabled - assert 404 == 403
 +  where 404 = <Response [404 Not Found]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 155 passed, 3 deselected, 1 warning in 2.60s
operator: core/NumberReplacer, occurrence: 29, definition_name: setup_page
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -387,7 +387,7 @@
         HTTPException: If setup is disabled (403).
     """
     if not settings.setup_enabled:
-        raise HTTPException(status_code=403, detail="Setup not allowed in this environment")
+        raise HTTPException(status_code= 402, detail="Setup not allowed in this environment")
 
     if is_configured():
         return HTMLResponse(
........................................................................ [ 30%]
........................................................................ [ 60%]
...........F
=================================== FAILURES ===================================
____________ TestSetupDisabled.test_setup_returns_403_when_disabled ____________

self = <tests.test_setup_endpoints.TestSetupDisabled object at 0x7f08d2048690>

    def test_setup_returns_403_when_disabled(self):
        """Test /setup returns 403 when setup is disabled."""
        with (
            patch("stampbot.main.is_configured", return_value=False),
            patch("stampbot.main.settings") as mock_settings,
        ):
            mock_settings.setup_enabled = False
    
            from fastapi.testclient import TestClient
    
            from stampbot.main import app
    
            client = TestClient(app, raise_server_exceptions=False)
            response = client.get("/setup")
    
>           assert response.status_code == 403
E           assert 402 == 403
E            +  where 402 = <Response [402 Payment Required]>.status_code

tests/test_setup_endpoints.py:287: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:30:00.794060Z [info     ] HTTP Request: GET http://testserver/setup "HTTP/1.1 402 Payment Required" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup "HTTP/1.1 402 Payment Required"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupDisabled::test_setup_returns_403_when_disabled - assert 402 == 403
 +  where 402 = <Response [402 Payment Required]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 155 passed, 3 deselected, 1 warning in 2.61s
operator: core/NumberReplacer, occurrence: 30, definition_name: setup_page
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -412,7 +412,7 @@
             </body>
             </html>
             """,
-            status_code=200,
+            status_code= 201,
         )
 
     # Determine base URL with priority:
........................................................................ [ 30%]
........................................................................ [ 60%]
.F
=================================== FAILURES ===================================
_______ TestSetupEndpointsConfigured.test_setup_shows_already_configured _______

self = <tests.test_setup_endpoints.TestSetupEndpointsConfigured object at 0x7fd14fc54050>
test_client = <starlette.testclient.TestClient object at 0x7fd14bc67130>

    def test_setup_shows_already_configured(self, test_client):
        """Test /setup shows already configured message."""
        response = test_client.get("/setup")
    
>       assert response.status_code == 200
E       assert 201 == 200
E        +  where 201 = <Response [201 Created]>.status_code

tests/test_setup_endpoints.py:68: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:37:35.944190Z [info     ] HTTP Request: GET http://testserver/setup "HTTP/1.1 201 Created" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup "HTTP/1.1 201 Created"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupEndpointsConfigured::test_setup_shows_already_configured - assert 201 == 200
 +  where 201 = <Response [201 Created]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 145 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 31, definition_name: setup_page
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -412,7 +412,7 @@
             </body>
             </html>
             """,
-            status_code=200,
+            status_code= 199,
         )
 
     # Determine base URL with priority:
........................................................................ [ 30%]
........................................................................ [ 60%]
.F
=================================== FAILURES ===================================
_______ TestSetupEndpointsConfigured.test_setup_shows_already_configured _______

self = <tests.test_setup_endpoints.TestSetupEndpointsConfigured object at 0x7f574de60050>
test_client = <starlette.testclient.TestClient object at 0x7f5749e3f130>

    def test_setup_shows_already_configured(self, test_client):
        """Test /setup shows already configured message."""
        response = test_client.get("/setup")
    
>       assert response.status_code == 200
E       assert 199 == 200
E        +  where 199 = <Response [199 ]>.status_code

tests/test_setup_endpoints.py:68: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:48:42.053554Z [info     ] HTTP Request: GET http://testserver/setup "HTTP/1.1 199 " [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup "HTTP/1.1 199 "
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupEndpointsConfigured::test_setup_shows_already_configured - assert 199 == 200
 +  where 199 = <Response [199 ]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 145 passed, 3 deselected, 1 warning in 2.55s
operator: core/NumberReplacer, occurrence: 32, definition_name: setup_callback
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -509,7 +509,7 @@
         HTTPException: If setup disabled (403) or code exchange fails (500).
     """
     if not settings.setup_enabled:
-        raise HTTPException(status_code=403, detail="Setup not allowed")
+        raise HTTPException(status_code= 404, detail="Setup not allowed")
 
     try:
         credentials = await exchange_code_for_credentials(code)
........................................................................ [ 30%]
........................................................................ [ 60%]
............F
=================================== FAILURES ===================================
_______ TestSetupDisabled.test_setup_callback_returns_403_when_disabled ________

self = <tests.test_setup_endpoints.TestSetupDisabled object at 0x7f47495d87d0>

    def test_setup_callback_returns_403_when_disabled(self):
        """Test /setup/callback returns 403 when setup is disabled."""
        with patch("stampbot.main.settings") as mock_settings:
            mock_settings.setup_enabled = False
    
            from fastapi.testclient import TestClient
    
            from stampbot.main import app
    
            client = TestClient(app, raise_server_exceptions=False)
            response = client.get("/setup/callback?code=test")
    
>           assert response.status_code == 403
E           assert 404 == 403
E            +  where 404 = <Response [404 Not Found]>.status_code

tests/test_setup_endpoints.py:301: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:30:41.897422Z [info     ] HTTP Request: GET http://testserver/setup/callback?code=test "HTTP/1.1 404 Not Found" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup/callback?code=test "HTTP/1.1 404 Not Found"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupDisabled::test_setup_callback_returns_403_when_disabled - assert 404 == 403
 +  where 404 = <Response [404 Not Found]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 156 passed, 3 deselected, 1 warning in 2.58s
operator: core/NumberReplacer, occurrence: 33, definition_name: setup_callback
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -509,7 +509,7 @@
         HTTPException: If setup disabled (403) or code exchange fails (500).
     """
     if not settings.setup_enabled:
-        raise HTTPException(status_code=403, detail="Setup not allowed")
+        raise HTTPException(status_code= 402, detail="Setup not allowed")
 
     try:
         credentials = await exchange_code_for_credentials(code)
........................................................................ [ 30%]
........................................................................ [ 60%]
............F
=================================== FAILURES ===================================
_______ TestSetupDisabled.test_setup_callback_returns_403_when_disabled ________

self = <tests.test_setup_endpoints.TestSetupDisabled object at 0x7f97498fc7d0>

    def test_setup_callback_returns_403_when_disabled(self):
        """Test /setup/callback returns 403 when setup is disabled."""
        with patch("stampbot.main.settings") as mock_settings:
            mock_settings.setup_enabled = False
    
            from fastapi.testclient import TestClient
    
            from stampbot.main import app
    
            client = TestClient(app, raise_server_exceptions=False)
            response = client.get("/setup/callback?code=test")
    
>           assert response.status_code == 403
E           assert 402 == 403
E            +  where 402 = <Response [402 Payment Required]>.status_code

tests/test_setup_endpoints.py:301: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:47:56.900457Z [info     ] HTTP Request: GET http://testserver/setup/callback?code=test "HTTP/1.1 402 Payment Required" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup/callback?code=test "HTTP/1.1 402 Payment Required"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupDisabled::test_setup_callback_returns_403_when_disabled - assert 402 == 403
 +  where 402 = <Response [402 Payment Required]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 156 passed, 3 deselected, 1 warning in 2.60s
operator: core/NumberReplacer, occurrence: 34, definition_name: setup_callback
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -515,7 +515,7 @@
         credentials = await exchange_code_for_credentials(code)
     except Exception as e:
         logger.error("Failed to exchange code for credentials: %s", _sanitize_error(e))
-        raise HTTPException(status_code=500, detail="Failed to complete setup") from None
+        raise HTTPException(status_code= 501, detail="Failed to complete setup") from None
 
     # Security note: Credentials are displayed in the HTML response for user convenience.
     # This mirrors GitHub's own manifest flow behavior. The tradeoffs are acceptable because:
........................................................................ [ 30%]
........................................................................ [ 60%]
..........F
=================================== FAILURES ===================================
____________ TestSetupCallback.test_callback_handles_exchange_error ____________

self = <tests.test_setup_endpoints.TestSetupCallback object at 0x7f0031824050>
test_client = <starlette.testclient.TestClient object at 0x7f002d9508d0>

    def test_callback_handles_exchange_error(self, test_client):
        """Test callback handles exchange error gracefully."""
        with patch(
            "stampbot.main.exchange_code_for_credentials",
            new_callable=AsyncMock,
            side_effect=Exception("API error"),
        ):
            response = test_client.get("/setup/callback?code=bad-code")
    
>           assert response.status_code == 500
E           assert 501 == 500
E            +  where 501 = <Response [501 Not Implemented]>.status_code

tests/test_setup_endpoints.py:266: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:42:21.684602Z [error    ] Failed to exchange code for credentials: API error [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=error client_ip=testclient
2026-06-29T04:42:21.685427Z [info     ] HTTP Request: GET http://testserver/setup/callback?code=bad-code "HTTP/1.1 501 Not Implemented" [httpx]
------------------------------ Captured log call -------------------------------
ERROR    stampbot.main:main.py:517 {'event': 'Failed to exchange code for credentials: API error', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'error', 'timestamp': '2026-06-29T04:42:21.684602Z'}
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup/callback?code=bad-code "HTTP/1.1 501 Not Implemented"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupCallback::test_callback_handles_exchange_error - assert 501 == 500
 +  where 501 = <Response [501 Not Implemented]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 154 passed, 3 deselected, 1 warning in 2.63s
operator: core/NumberReplacer, occurrence: 35, definition_name: setup_callback
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -515,7 +515,7 @@
         credentials = await exchange_code_for_credentials(code)
     except Exception as e:
         logger.error("Failed to exchange code for credentials: %s", _sanitize_error(e))
-        raise HTTPException(status_code=500, detail="Failed to complete setup") from None
+        raise HTTPException(status_code= 499, detail="Failed to complete setup") from None
 
     # Security note: Credentials are displayed in the HTML response for user convenience.
     # This mirrors GitHub's own manifest flow behavior. The tradeoffs are acceptable because:
........................................................................ [ 30%]
........................................................................ [ 60%]
..........F
=================================== FAILURES ===================================
____________ TestSetupCallback.test_callback_handles_exchange_error ____________

self = <tests.test_setup_endpoints.TestSetupCallback object at 0x7f3b38ffc050>
test_client = <starlette.testclient.TestClient object at 0x7f3b350808d0>

    def test_callback_handles_exchange_error(self, test_client):
        """Test callback handles exchange error gracefully."""
        with patch(
            "stampbot.main.exchange_code_for_credentials",
            new_callable=AsyncMock,
            side_effect=Exception("API error"),
        ):
            response = test_client.get("/setup/callback?code=bad-code")
    
>           assert response.status_code == 500
E           assert 499 == 500
E            +  where 499 = <Response [499 ]>.status_code

tests/test_setup_endpoints.py:266: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:26:10.447025Z [error    ] Failed to exchange code for credentials: API error [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=error client_ip=testclient
2026-06-29T04:26:10.447884Z [info     ] HTTP Request: GET http://testserver/setup/callback?code=bad-code "HTTP/1.1 499 " [httpx]
------------------------------ Captured log call -------------------------------
ERROR    stampbot.main:main.py:517 {'event': 'Failed to exchange code for credentials: API error', 'client_ip': 'testclient', 'logger': 'stampbot.main', 'level': 'error', 'timestamp': '2026-06-29T04:26:10.447025Z'}
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup/callback?code=bad-code "HTTP/1.1 499 "
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupCallback::test_callback_handles_exchange_error - assert 499 == 500
 +  where 499 = <Response [499 ]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 154 passed, 3 deselected, 1 warning in 2.59s
operator: core/RemoveDecorator, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -53,9 +53,6 @@
 
 # Security limits
 MAX_WEBHOOK_BODY_SIZE = 1024 * 1024  # 1MB - GitHub webhooks are typically much smaller
-
-
-@asynccontextmanager
 async def lifespan(app: FastAPI) -> AsyncIterator[None]:
     """Application lifespan manager for startup and shutdown events.
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/RemoveDecorator, occurrence: 1, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -100,9 +100,6 @@
 
 # Set app info metric
 set_app_info(APP_VERSION)
-
-
-@app.middleware("http")
 async def metrics_middleware(request: Request, call_next: Any) -> Response:
     """Middleware to track HTTP metrics.
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/RemoveDecorator, occurrence: 2, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -211,9 +211,6 @@
 
 
 app.add_middleware(LoggingMiddleware)
-
-
-@app.get("/")
 async def root() -> Response:
     """Root endpoint - redirects to setup if not configured.
 
........................................................................ [ 30%]
.............................F
=================================== FAILURES ===================================
______________________________ test_root_endpoint ______________________________

test_client = <starlette.testclient.TestClient object at 0x7f016afd3750>

    def test_root_endpoint(test_client: TestClient):
        """Test root endpoint returns basic info."""
        response = test_client.get("/")
>       assert response.status_code == 200
E       assert 404 == 200
E        +  where 404 = <Response [404 Not Found]>.status_code

tests/test_main.py:45: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:29:29.959351Z [info     ] HTTP Request: GET http://testserver/ "HTTP/1.1 404 Not Found" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/ "HTTP/1.1 404 Not Found"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_root_endpoint - assert 404 == 200
 +  where 404 = <Response [404 Not Found]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 101 passed, 3 deselected, 1 warning in 2.35s
operator: core/RemoveDecorator, occurrence: 3, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -227,9 +227,6 @@
         content='{"app": "stampbot", "version": "' + APP_VERSION + '", "status": "running"}',
         media_type="application/json",
     )
-
-
-@app.get("/health")
 async def health() -> dict[str, str]:
     """Liveness check endpoint.
 
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
        from stampbot.main import app
    
        # Use TestClient as context manager to trigger lifespan events
        with TestClient(app) as client:
            # App should be running
            response = client.get("/health")
>           assert response.status_code == 200
E           assert 404 == 200
E            +  where 404 = <Response [404 Not Found]>.status_code

tests/test_main.py:21: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:49:29.881063Z [info     ] OpenTelemetry disabled         [stampbot.telemetry] _logger=<_FixedFindCallerLogger stampbot.telemetry (INFO)> _name=info
2026-06-29T05:49:30.002790Z [info     ] Starting stampbot on 0.0.0.0:8000 [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info extra={'host': '0.0.0.0', 'port': 8000, 'log_level': 'INFO'}
2026-06-29T05:49:30.003095Z [info     ] GitHub App credentials configured successfully [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
2026-06-29T05:49:30.005095Z [info     ] HTTP Request: GET http://testserver/health "HTTP/1.1 404 Not Found" [httpx]
2026-06-29T05:49:30.005617Z [info     ] Shutting down stampbot         [stampbot.main] _logger=<_FixedFindCallerLogger stampbot.main (INFO)> _name=info
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - assert 404 == 200
 +  where 404 = <Response [404 Not Found]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.31s
operator: core/RemoveDecorator, occurrence: 4, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -242,9 +242,6 @@
         Dictionary with health status.
     """
     return {"status": "healthy"}
-
-
-@app.get("/ready")
 async def ready() -> Response:
     """Readiness check endpoint.
 
........................................................................ [ 30%]
...............................F
=================================== FAILURES ===================================
________________________ test_ready_endpoint_configured ________________________

test_client = <starlette.testclient.TestClient object at 0x7fc53576f820>

    def test_ready_endpoint_configured(test_client: TestClient):
        """Test readiness endpoint returns 200 when the app is configured."""
        with patch("stampbot.main.is_configured", return_value=True):
            response = test_client.get("/ready")
>       assert response.status_code == 200
E       assert 404 == 200
E        +  where 404 = <Response [404 Not Found]>.status_code

tests/test_main.py:63: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:51:23.890137Z [info     ] HTTP Request: GET http://testserver/ready "HTTP/1.1 404 Not Found" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/ready "HTTP/1.1 404 Not Found"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_ready_endpoint_configured - assert 404 == 200
 +  where 404 = <Response [404 Not Found]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 103 passed, 3 deselected, 1 warning in 2.35s
operator: core/RemoveDecorator, occurrence: 5, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -273,9 +273,6 @@
         status_code=200 if is_ready else 503,
         content={"status": "ready" if is_ready else "not ready", "checks": checks},
     )
-
-
-@app.get("/metrics")
 async def metrics() -> Response:
     """Prometheus metrics endpoint.
 
........................................................................ [ 30%]
..................................F
=================================== FAILURES ===================================
____________________________ test_metrics_endpoint _____________________________

test_client = <starlette.testclient.TestClient object at 0x7f65fef75480>

    def test_metrics_endpoint(test_client: TestClient):
        """Test Prometheus metrics endpoint."""
        response = test_client.get("/metrics")
>       assert response.status_code == 200
E       assert 404 == 200
E        +  where 404 = <Response [404 Not Found]>.status_code

tests/test_main.py:104: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:37:19.947547Z [info     ] HTTP Request: GET http://testserver/metrics "HTTP/1.1 404 Not Found" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/metrics "HTTP/1.1 404 Not Found"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_metrics_endpoint - assert 404 == 200
 +  where 404 = <Response [404 Not Found]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 106 passed, 3 deselected, 1 warning in 2.33s
operator: core/RemoveDecorator, occurrence: 6, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -286,9 +286,6 @@
         content=get_metrics().decode("utf-8"),
         media_type="text/plain",
     )
-
-
-@app.post("/webhook")
 async def webhook(
     request: Request,
     x_github_event: str = Header(None, alias="X-GitHub-Event"),
........................................................................ [ 30%]
...................................F
=================================== FAILURES ===================================
_______________________ test_request_with_content_length _______________________

test_client = <starlette.testclient.TestClient object at 0x7fb426789e10>

    def test_request_with_content_length(test_client: TestClient):
        """Test that requests with Content-Length header are tracked."""
        # POST with a body will have Content-Length set automatically
        response = test_client.post(
            "/webhook",
            content=b'{"test": "data"}',
            headers={
                "Content-Type": "application/json",
                "X-GitHub-Event": "ping",
                "X-Hub-Signature-256": "sha256=invalid",
            },
        )
        # Will fail signature validation, but Content-Length tracking happens before that
>       assert response.status_code == 401
E       assert 404 == 401
E        +  where 404 = <Response [404 Not Found]>.status_code

tests/test_main.py:121: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:23:07.814024Z [info     ] HTTP Request: POST http://testserver/webhook "HTTP/1.1 404 Not Found" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: POST http://testserver/webhook "HTTP/1.1 404 Not Found"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_request_with_content_length - assert 404 == 401
 +  where 404 = <Response [404 Not Found]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 107 passed, 3 deselected, 1 warning in 2.35s
operator: core/RemoveDecorator, occurrence: 7, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -366,14 +366,6 @@
         sanitized = _sanitize_error(e)
         logger.error("Error handling webhook event: %s", sanitized, extra={"error": sanitized})
         raise HTTPException(status_code=500, detail="Internal server error") from None
-
-
-# =============================================================================
-# Setup Endpoints - GitHub App Manifest Flow
-# =============================================================================
-
-
-@app.get("/setup")
 async def setup_page(request: Request) -> Response:
     """Setup page with manifest creation button.
 
........................................................................ [ 30%]
........................................................................ [ 60%]
.F
=================================== FAILURES ===================================
_______ TestSetupEndpointsConfigured.test_setup_shows_already_configured _______

self = <tests.test_setup_endpoints.TestSetupEndpointsConfigured object at 0x7f7362354050>
test_client = <starlette.testclient.TestClient object at 0x7f735e363130>

    def test_setup_shows_already_configured(self, test_client):
        """Test /setup shows already configured message."""
        response = test_client.get("/setup")
    
>       assert response.status_code == 200
E       assert 404 == 200
E        +  where 404 = <Response [404 Not Found]>.status_code

tests/test_setup_endpoints.py:68: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:29:41.693167Z [info     ] HTTP Request: GET http://testserver/setup "HTTP/1.1 404 Not Found" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup "HTTP/1.1 404 Not Found"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupEndpointsConfigured::test_setup_shows_already_configured - assert 404 == 200
 +  where 404 = <Response [404 Not Found]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 145 passed, 3 deselected, 1 warning in 2.56s
operator: core/RemoveDecorator, occurrence: 8, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -492,9 +492,6 @@
     """
 
     return HTMLResponse(content=html_content)
-
-
-@app.get("/setup/callback")
 async def setup_callback(request: Request, code: str) -> Response:
     """Handle callback from GitHub after app creation.
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........F
=================================== FAILURES ===================================
________________ TestSetupCallback.test_callback_exchanges_code ________________

self = <tests.test_setup_endpoints.TestSetupCallback object at 0x7f308c170410>
test_client = <starlette.testclient.TestClient object at 0x7f308829d040>

    def test_callback_exchanges_code(self, test_client):
        """Test callback exchanges code for credentials."""
        mock_credentials = {
            "id": 12345,
            "pem": "-----BEGIN RSA PRIVATE KEY-----\ntest\n-----END RSA PRIVATE KEY-----",
            "webhook_secret": "test-secret",
            "slug": "test-stampbot",
            "name": "Test Stampbot",
        }
    
        with patch(
            "stampbot.main.exchange_code_for_credentials",
            new_callable=AsyncMock,
            return_value=mock_credentials,
        ):
            response = test_client.get("/setup/callback?code=test-code")
    
>           assert response.status_code == 200
E           assert 404 == 200
E            +  where 404 = <Response [404 Not Found]>.status_code

tests/test_setup_endpoints.py:230: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T04:50:29.253817Z [info     ] HTTP Request: GET http://testserver/setup/callback?code=test-code "HTTP/1.1 404 Not Found" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup/callback?code=test-code "HTTP/1.1 404 Not Found"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupCallback::test_callback_exchanges_code - assert 404 == 200
 +  where 404 = <Response [404 Not Found]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 152 passed, 3 deselected, 1 warning in 2.58s
operator: core/RemoveDecorator, occurrence: 9, definition_name: None
--- mutation diff ---
--- astampbot/main.py
+++ bstampbot/main.py
@@ -605,9 +605,6 @@
     """
 
     return HTMLResponse(content=html_content)
-
-
-@app.get("/setup/status")
 async def setup_status() -> dict[str, Any]:
     """Check setup status.
 
........................................................................ [ 30%]
........................................................................ [ 60%]
..F
=================================== FAILURES ===================================
_______ TestSetupEndpointsConfigured.test_setup_status_shows_configured ________

self = <tests.test_setup_endpoints.TestSetupEndpointsConfigured object at 0x7f63b7b63490>
test_client = <starlette.testclient.TestClient object at 0x7f63b3a3f570>

    def test_setup_status_shows_configured(self, test_client):
        """Test /setup/status shows configured status."""
        response = test_client.get("/setup/status")
    
>       assert response.status_code == 200
E       assert 404 == 200
E        +  where 404 = <Response [404 Not Found]>.status_code

tests/test_setup_endpoints.py:75: AssertionError
----------------------------- Captured stdout call -----------------------------
2026-06-29T05:12:26.281589Z [info     ] HTTP Request: GET http://testserver/setup/status "HTTP/1.1 404 Not Found" [httpx]
------------------------------ Captured log call -------------------------------
INFO     httpx:_client.py:1025 HTTP Request: GET http://testserver/setup/status "HTTP/1.1 404 Not Found"
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_setup_endpoints.py::TestSetupEndpointsConfigured::test_setup_status_shows_configured - assert 404 == 200
 +  where 404 = <Response [404 Not Found]>.status_code
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 146 passed, 3 deselected, 1 warning in 2.58s
operator: core/ReplaceBinaryOperator_Pow_Add, occurrence: 0, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {+defaults, **repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {+defaults, **repo_settings}
E                            ^^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_Add, occurrence: 1, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {**defaults, +repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {**defaults, +repo_settings}
E                                          ^
E   SyntaxError: ':' expected after dictionary key
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.14s
operator: core/ReplaceBinaryOperator_Pow_Sub, occurrence: 0, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {-defaults, **repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {-defaults, **repo_settings}
E                            ^^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_Sub, occurrence: 1, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {**defaults, -repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {**defaults, -repo_settings}
E                                          ^
E   SyntaxError: ':' expected after dictionary key
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.14s
operator: core/ReplaceBinaryOperator_Pow_Mul, occurrence: 0, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {*defaults, **repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {*defaults, **repo_settings}
E                            ^^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_Mul, occurrence: 1, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {**defaults, *repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {**defaults, *repo_settings}
E                             ^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_Div, occurrence: 0, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {/defaults, **repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {/defaults, **repo_settings}
E                 ^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_Div, occurrence: 1, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {**defaults, /repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {**defaults, /repo_settings}
E                             ^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_FloorDiv, occurrence: 0, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {//defaults, **repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {//defaults, **repo_settings}
E                 ^^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_FloorDiv, occurrence: 1, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {**defaults, //repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {**defaults, //repo_settings}
E                             ^^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_Mod, occurrence: 0, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {%defaults, **repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {%defaults, **repo_settings}
E                 ^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_Mod, occurrence: 1, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {**defaults, %repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {**defaults, %repo_settings}
E                             ^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_RShift, occurrence: 0, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {>>defaults, **repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {>>defaults, **repo_settings}
E                 ^^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_RShift, occurrence: 1, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {**defaults, >>repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {**defaults, >>repo_settings}
E                             ^^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_LShift, occurrence: 0, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {<<defaults, **repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {<<defaults, **repo_settings}
E                 ^^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.17s
operator: core/ReplaceBinaryOperator_Pow_LShift, occurrence: 1, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {**defaults, <<repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {**defaults, <<repo_settings}
E                             ^^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_BitOr, occurrence: 0, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {|defaults, **repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {|defaults, **repo_settings}
E                 ^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_BitOr, occurrence: 1, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {**defaults, |repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {**defaults, |repo_settings}
E                             ^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_BitAnd, occurrence: 0, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {&defaults, **repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {&defaults, **repo_settings}
E                 ^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_BitAnd, occurrence: 1, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {**defaults, &repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {**defaults, &repo_settings}
E                             ^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_BitXor, occurrence: 0, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {^defaults, **repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {^defaults, **repo_settings}
E                 ^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceBinaryOperator_Pow_BitXor, occurrence: 1, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -258,7 +258,7 @@
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
-        merged = {**defaults, **repo_settings}
+        merged = {**defaults, ^repo_settings}
 
         import re
 
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_config.py _____________________
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/python.py:507: in importtestmodule
    mod = import_path(
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/pathlib.py:587: in import_path
    importlib.import_module(module_name)
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/importlib/__init__.py:88: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<frozen importlib._bootstrap>:1406: in _gcd_import
    ???
<frozen importlib._bootstrap>:1371: in _find_and_load
    ???
<frozen importlib._bootstrap>:1342: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:938: in _load_unlocked
    ???
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
    exec(co, module.__dict__)
tests/test_config.py:7: in <module>
    from stampbot.config import RepoConfig, get_setting, is_configured
E     File "/home/runner/work/stampbot/stampbot/stampbot/config.py", line 261
E       merged = {**defaults, ^repo_settings}
E                             ^
E   SyntaxError: invalid syntax
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
ERROR tests/test_config.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 warning, 1 error in 0.15s
operator: core/ReplaceUnaryOperator_USub_UAdd, occurrence: 0, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -181,7 +181,7 @@
             if self.allowed_teams and author_team_slugs:
                 for team in self.allowed_teams:
                     # Support both "org/team" and "team" formats
-                    team_slug = team.split("/")[-1] if "/" in team else team
+                    team_slug = team.split("/")[+1] if "/" in team else team
                     if team_slug in author_team_slugs:
                         return True, None
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceUnaryOperator_USub_Invert, occurrence: 0, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -181,7 +181,7 @@
             if self.allowed_teams and author_team_slugs:
                 for team in self.allowed_teams:
                     # Support both "org/team" and "team" formats
-                    team_slug = team.split("/")[-1] if "/" in team else team
+                    team_slug = team.split("/")[~1] if "/" in team else team
                     if team_slug in author_team_slugs:
                         return True, None
 
...........................F
=================================== FAILURES ===================================
_______________________ test_is_pr_eligible_allowed_team _______________________

    def test_is_pr_eligible_allowed_team():
        """Test is_pr_eligible returns True when author is in an allowed team."""
        config = RepoConfig.from_toml('allowed_teams = ["my-org/release-team"]')
        is_eligible, reason = config.is_pr_eligible(
            [], "Update deps", "team-member", author_team_slugs=["release-team"]
        )
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:321: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_allowed_team - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 27 passed, 3 deselected, 1 warning in 0.95s
operator: core/ReplaceUnaryOperator_USub_Not, occurrence: 0, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -181,7 +181,7 @@
             if self.allowed_teams and author_team_slugs:
                 for team in self.allowed_teams:
                     # Support both "org/team" and "team" formats
-                    team_slug = team.split("/")[-1] if "/" in team else team
+                    team_slug = team.split("/")[not 1] if "/" in team else team
                     if team_slug in author_team_slugs:
                         return True, None
 
...........................F
=================================== FAILURES ===================================
_______________________ test_is_pr_eligible_allowed_team _______________________

    def test_is_pr_eligible_allowed_team():
        """Test is_pr_eligible returns True when author is in an allowed team."""
        config = RepoConfig.from_toml('allowed_teams = ["my-org/release-team"]')
        is_eligible, reason = config.is_pr_eligible(
            [], "Update deps", "team-member", author_team_slugs=["release-team"]
        )
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:321: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_allowed_team - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 27 passed, 3 deselected, 1 warning in 0.95s
operator: core/ReplaceUnaryOperator_Delete_USub, occurrence: 0, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -181,7 +181,7 @@
             if self.allowed_teams and author_team_slugs:
                 for team in self.allowed_teams:
                     # Support both "org/team" and "team" formats
-                    team_slug = team.split("/")[-1] if "/" in team else team
+                    team_slug = team.split("/")[1] if "/" in team else team
                     if team_slug in author_team_slugs:
                         return True, None
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 0, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -160,7 +160,7 @@
 
         # Check required labels filter
         if self.required_labels:
-            if not any(label in self.required_labels for label in pr_labels):
+            if  any(label in self.required_labels for label in pr_labels):
                 return (
                     False,
                     f"PR missing required label (one of: {', '.join(self.required_labels)})",
................F
=================================== FAILURES ===================================
__________________ test_is_pr_eligible_required_label_present __________________

    def test_is_pr_eligible_required_label_present():
        """Test is_pr_eligible returns True when required label is present."""
        config = RepoConfig.from_toml('required_labels = ["dependencies", "automated"]')
        is_eligible, reason = config.is_pr_eligible(["dependencies"], "PR title", "someuser")
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:215: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_required_label_present - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 16 passed, 3 deselected, 1 warning in 0.95s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 1, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -168,7 +168,7 @@
 
         # Check required title patterns filter
         if self.required_title_patterns:
-            if not any(re.search(pattern, pr_title) for pattern in self.required_title_patterns):
+            if  any(re.search(pattern, pr_title) for pattern in self.required_title_patterns):
                 return False, "PR title does not match any required pattern"
 
         # Check allowed users/teams filter (if either is configured)
...................F
=================================== FAILURES ===================================
__________________ test_is_pr_eligible_title_pattern_matches ___________________

    def test_is_pr_eligible_title_pattern_matches():
        """Test is_pr_eligible returns True when title matches pattern."""
        config = RepoConfig.from_toml('required_title_patterns = ["^chore:", "^\\\\[bot\\\\]"]')
        is_eligible, reason = config.is_pr_eligible([], "chore: update dependencies", "someuser")
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:240: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_title_pattern_matches - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 19 passed, 3 deselected, 1 warning in 0.94s
operator: core/ReplaceUnaryOperator_Delete_Not, occurrence: 2, definition_name: needs_team_check
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -204,7 +204,7 @@
         Returns:
             True if team check is needed (author not in allowed_users but teams configured)
         """
-        if not self.allowed_teams:
+        if  self.allowed_teams:
             return False
         if self.allowed_users and pr_author in self.allowed_users:
             return False
.................................F
=================================== FAILURES ===================================
__________________ test_needs_team_check_no_teams_configured ___________________

    def test_needs_team_check_no_teams_configured():
        """Test needs_team_check returns False when no teams configured."""
        config = RepoConfig.from_toml('allowed_users = ["some-user"]')
>       assert config.needs_team_check("any-user") is False
E       AssertionError: assert True is False
E        +  where True = needs_team_check('any-user')
E        +    where needs_team_check = <stampbot.config.RepoConfig object at 0x7f0eeeb8b120>.needs_team_check

tests/test_config.py:393: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_needs_team_check_no_teams_configured - AssertionError: assert True is False
 +  where True = needs_team_check('any-user')
 +    where needs_team_check = <stampbot.config.RepoConfig object at 0x7f0eeeb8b120>.needs_team_check
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 33 passed, 3 deselected, 1 warning in 0.96s
operator: core/AddNot, occurrence: 0, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -159,7 +159,7 @@
         import re
 
         # Check required labels filter
-        if self.required_labels:
+        if not self.required_labels:
             if not any(label in self.required_labels for label in pr_labels):
                 return (
                     False,
...............F
=================================== FAILURES ===================================
________________________ test_is_pr_eligible_no_filters ________________________

    def test_is_pr_eligible_no_filters():
        """Test is_pr_eligible returns True when no filters configured."""
        config = RepoConfig.default()
        is_eligible, reason = config.is_pr_eligible(["some-label"], "Some PR title", "someuser")
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:207: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_no_filters - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 15 passed, 3 deselected, 1 warning in 0.96s
operator: core/AddNot, occurrence: 1, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -160,7 +160,7 @@
 
         # Check required labels filter
         if self.required_labels:
-            if not any(label in self.required_labels for label in pr_labels):
+            if not not any(label in self.required_labels for label in pr_labels):
                 return (
                     False,
                     f"PR missing required label (one of: {', '.join(self.required_labels)})",
................F
=================================== FAILURES ===================================
__________________ test_is_pr_eligible_required_label_present __________________

    def test_is_pr_eligible_required_label_present():
        """Test is_pr_eligible returns True when required label is present."""
        config = RepoConfig.from_toml('required_labels = ["dependencies", "automated"]')
        is_eligible, reason = config.is_pr_eligible(["dependencies"], "PR title", "someuser")
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:215: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_required_label_present - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 16 passed, 3 deselected, 1 warning in 0.94s
operator: core/AddNot, occurrence: 2, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -167,7 +167,7 @@
                 )
 
         # Check required title patterns filter
-        if self.required_title_patterns:
+        if not self.required_title_patterns:
             if not any(re.search(pattern, pr_title) for pattern in self.required_title_patterns):
                 return False, "PR title does not match any required pattern"
 
...............F
=================================== FAILURES ===================================
________________________ test_is_pr_eligible_no_filters ________________________

    def test_is_pr_eligible_no_filters():
        """Test is_pr_eligible returns True when no filters configured."""
        config = RepoConfig.default()
        is_eligible, reason = config.is_pr_eligible(["some-label"], "Some PR title", "someuser")
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:207: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_no_filters - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 15 passed, 3 deselected, 1 warning in 0.94s
operator: core/AddNot, occurrence: 3, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -168,7 +168,7 @@
 
         # Check required title patterns filter
         if self.required_title_patterns:
-            if not any(re.search(pattern, pr_title) for pattern in self.required_title_patterns):
+            if not not any(re.search(pattern, pr_title) for pattern in self.required_title_patterns):
                 return False, "PR title does not match any required pattern"
 
         # Check allowed users/teams filter (if either is configured)
...................F
=================================== FAILURES ===================================
__________________ test_is_pr_eligible_title_pattern_matches ___________________

    def test_is_pr_eligible_title_pattern_matches():
        """Test is_pr_eligible returns True when title matches pattern."""
        config = RepoConfig.from_toml('required_title_patterns = ["^chore:", "^\\\\[bot\\\\]"]')
        is_eligible, reason = config.is_pr_eligible([], "chore: update dependencies", "someuser")
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:240: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_title_pattern_matches - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 19 passed, 3 deselected, 1 warning in 0.95s
operator: core/AddNot, occurrence: 4, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -172,7 +172,7 @@
                 return False, "PR title does not match any required pattern"
 
         # Check allowed users/teams filter (if either is configured)
-        if self.allowed_users or self.allowed_teams:
+        if not self.allowed_users or self.allowed_teams:
             # User is allowed if they're in allowed_users
             if pr_author in self.allowed_users:
                 return True, None
...............F
=================================== FAILURES ===================================
________________________ test_is_pr_eligible_no_filters ________________________

    def test_is_pr_eligible_no_filters():
        """Test is_pr_eligible returns True when no filters configured."""
        config = RepoConfig.default()
        is_eligible, reason = config.is_pr_eligible(["some-label"], "Some PR title", "someuser")
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:207: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_no_filters - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 15 passed, 3 deselected, 1 warning in 0.95s
operator: core/AddNot, occurrence: 5, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -174,7 +174,7 @@
         # Check allowed users/teams filter (if either is configured)
         if self.allowed_users or self.allowed_teams:
             # User is allowed if they're in allowed_users
-            if pr_author in self.allowed_users:
+            if not pr_author in self.allowed_users:
                 return True, None
 
             # Or if they're a member of an allowed team
.........................F
=================================== FAILURES ===================================
_______________________ test_is_pr_eligible_allowed_user _______________________

    def test_is_pr_eligible_allowed_user():
        """Test is_pr_eligible returns True when author is in allowed_users."""
        config = RepoConfig.from_toml('allowed_users = ["dependabot[bot]", "renovate[bot]"]')
        is_eligible, reason = config.is_pr_eligible([], "Update deps", "dependabot[bot]")
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:303: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_allowed_user - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 25 passed, 3 deselected, 1 warning in 0.95s
operator: core/AddNot, occurrence: 6, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -178,7 +178,7 @@
                 return True, None
 
             # Or if they're a member of an allowed team
-            if self.allowed_teams and author_team_slugs:
+            if not self.allowed_teams and author_team_slugs:
                 for team in self.allowed_teams:
                     # Support both "org/team" and "team" formats
                     team_slug = team.split("/")[-1] if "/" in team else team
...........................F
=================================== FAILURES ===================================
_______________________ test_is_pr_eligible_allowed_team _______________________

    def test_is_pr_eligible_allowed_team():
        """Test is_pr_eligible returns True when author is in an allowed team."""
        config = RepoConfig.from_toml('allowed_teams = ["my-org/release-team"]')
        is_eligible, reason = config.is_pr_eligible(
            [], "Update deps", "team-member", author_team_slugs=["release-team"]
        )
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:321: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_allowed_team - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 27 passed, 3 deselected, 1 warning in 0.95s
operator: core/AddNot, occurrence: 7, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -181,7 +181,7 @@
             if self.allowed_teams and author_team_slugs:
                 for team in self.allowed_teams:
                     # Support both "org/team" and "team" formats
-                    team_slug = team.split("/")[-1] if "/" in team else team
+                    team_slug = team.split("/")[-1] if not "/" in team else team
                     if team_slug in author_team_slugs:
                         return True, None
 
...........................F
=================================== FAILURES ===================================
_______________________ test_is_pr_eligible_allowed_team _______________________

    def test_is_pr_eligible_allowed_team():
        """Test is_pr_eligible returns True when author is in an allowed team."""
        config = RepoConfig.from_toml('allowed_teams = ["my-org/release-team"]')
        is_eligible, reason = config.is_pr_eligible(
            [], "Update deps", "team-member", author_team_slugs=["release-team"]
        )
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:321: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_allowed_team - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 27 passed, 3 deselected, 1 warning in 0.96s
operator: core/AddNot, occurrence: 8, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -182,7 +182,7 @@
                 for team in self.allowed_teams:
                     # Support both "org/team" and "team" formats
                     team_slug = team.split("/")[-1] if "/" in team else team
-                    if team_slug in author_team_slugs:
+                    if not team_slug in author_team_slugs:
                         return True, None
 
             # Neither user nor team matched
...........................F
=================================== FAILURES ===================================
_______________________ test_is_pr_eligible_allowed_team _______________________

    def test_is_pr_eligible_allowed_team():
        """Test is_pr_eligible returns True when author is in an allowed team."""
        config = RepoConfig.from_toml('allowed_teams = ["my-org/release-team"]')
        is_eligible, reason = config.is_pr_eligible(
            [], "Update deps", "team-member", author_team_slugs=["release-team"]
        )
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:321: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_allowed_team - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 27 passed, 3 deselected, 1 warning in 0.96s
operator: core/AddNot, occurrence: 9, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -186,7 +186,7 @@
                         return True, None
 
             # Neither user nor team matched
-            if self.allowed_users and self.allowed_teams:
+            if not self.allowed_users and self.allowed_teams:
                 return False, "PR author not in allowed users or teams"
             elif self.allowed_users:
                 return False, f"PR author not in allowed users: {', '.join(self.allowed_users)}"
............................F
=================================== FAILURES ===================================
_____________________ test_is_pr_eligible_team_not_matched _____________________

    def test_is_pr_eligible_team_not_matched():
        """Test is_pr_eligible returns False when author is not in any allowed team."""
        config = RepoConfig.from_toml('allowed_teams = ["my-org/release-team"]')
        is_eligible, reason = config.is_pr_eligible(
            [], "Update deps", "non-member", author_team_slugs=["other-team"]
        )
        assert is_eligible is False
>       assert "not a member of any allowed team" in reason
E       AssertionError: assert 'not a member of any allowed team' in 'PR author not in allowed users or teams'

tests/test_config.py:332: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_team_not_matched - AssertionError: assert 'not a member of any allowed team' in 'PR author not in allowed users or teams'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 28 passed, 3 deselected, 1 warning in 0.96s
operator: core/AddNot, occurrence: 10, definition_name: needs_team_check
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -204,7 +204,7 @@
         Returns:
             True if team check is needed (author not in allowed_users but teams configured)
         """
-        if not self.allowed_teams:
+        if not not self.allowed_teams:
             return False
         if self.allowed_users and pr_author in self.allowed_users:
             return False
.................................F
=================================== FAILURES ===================================
__________________ test_needs_team_check_no_teams_configured ___________________

    def test_needs_team_check_no_teams_configured():
        """Test needs_team_check returns False when no teams configured."""
        config = RepoConfig.from_toml('allowed_users = ["some-user"]')
>       assert config.needs_team_check("any-user") is False
E       AssertionError: assert True is False
E        +  where True = needs_team_check('any-user')
E        +    where needs_team_check = <stampbot.config.RepoConfig object at 0x7faed219f120>.needs_team_check

tests/test_config.py:393: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_needs_team_check_no_teams_configured - AssertionError: assert True is False
 +  where True = needs_team_check('any-user')
 +    where needs_team_check = <stampbot.config.RepoConfig object at 0x7faed219f120>.needs_team_check
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 33 passed, 3 deselected, 1 warning in 0.96s
operator: core/AddNot, occurrence: 11, definition_name: needs_team_check
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -206,7 +206,7 @@
         """
         if not self.allowed_teams:
             return False
-        if self.allowed_users and pr_author in self.allowed_users:
+        if not self.allowed_users and pr_author in self.allowed_users:
             return False
         return True
 
..................................F
=================================== FAILURES ===================================
_________________ test_needs_team_check_user_in_allowed_users __________________

    def test_needs_team_check_user_in_allowed_users():
        """Test needs_team_check returns False when user is in allowed_users."""
        toml_content = """
    allowed_users = ["special-user"]
    allowed_teams = ["my-org/release-team"]
    """
        config = RepoConfig.from_toml(toml_content)
>       assert config.needs_team_check("special-user") is False
E       AssertionError: assert True is False
E        +  where True = needs_team_check('special-user')
E        +    where needs_team_check = <stampbot.config.RepoConfig object at 0x7fa251177330>.needs_team_check

tests/test_config.py:403: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_needs_team_check_user_in_allowed_users - AssertionError: assert True is False
 +  where True = needs_team_check('special-user')
 +    where needs_team_check = <stampbot.config.RepoConfig object at 0x7fa251177330>.needs_team_check
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 34 passed, 3 deselected, 1 warning in 0.96s
operator: core/AddNot, occurrence: 12, definition_name: _get_defaults
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -222,7 +222,7 @@
         defaults = REPO_CONFIG_DEFAULTS.copy()
 
         # Allow overriding defaults via settings.toml [defaults] section
-        if settings.get("defaults"):
+        if not settings.get("defaults"):
             settings_defaults = settings.defaults
             for key in defaults:
                 if hasattr(settings_defaults, key):
.........F
=================================== FAILURES ===================================
_____________ test_repo_config_get_defaults_with_settings_override _____________

    def test_repo_config_get_defaults_with_settings_override():
        """Test _get_defaults respects settings.toml overrides."""
        with patch("stampbot.config.settings") as mock_settings:
            # Create a mock defaults object with only specific attributes
            # Using spec=[] means hasattr will return False for most attributes
            mock_defaults = MagicMock(
                spec=["approval_labels", "chatops_enabled", "chatops_required_permission"]
            )
            mock_defaults.approval_labels = ["custom-label"]
            mock_defaults.chatops_enabled = False
            mock_defaults.chatops_required_permission = "write"
    
            mock_settings.get.return_value = mock_defaults
            mock_settings.defaults = mock_defaults
    
            defaults = RepoConfig._get_defaults()
    
            # Should have the overridden values
>           assert defaults["approval_labels"] == ["custom-label"]
E           AssertionError: assert ['autoapprove', 'stamp'] == ['custom-label']
E             
E             At index 0 diff: 'autoapprove' != 'custom-label'
E             Left contains one more item: 'stamp'
E             
E             Full diff:
E               [
E             -     'custom-label',
E             +     'autoapprove',
E             +     'stamp',
E               ]

tests/test_config.py:132: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_repo_config_get_defaults_with_settings_override - AssertionError: assert ['autoapprove', 'stamp'] == ['custom-label']
  
  At index 0 diff: 'autoapprove' != 'custom-label'
  Left contains one more item: 'stamp'
  
  Full diff:
    [
  -     'custom-label',
  +     'autoapprove',
  +     'stamp',
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 9 passed, 3 deselected, 1 warning in 0.94s
operator: core/AddNot, occurrence: 13, definition_name: _get_defaults
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -225,7 +225,7 @@
         if settings.get("defaults"):
             settings_defaults = settings.defaults
             for key in defaults:
-                if hasattr(settings_defaults, key):
+                if not hasattr(settings_defaults, key):
                     defaults[key] = getattr(settings_defaults, key)
 
         return defaults
.........F
=================================== FAILURES ===================================
_____________ test_repo_config_get_defaults_with_settings_override _____________

    def test_repo_config_get_defaults_with_settings_override():
        """Test _get_defaults respects settings.toml overrides."""
        with patch("stampbot.config.settings") as mock_settings:
            # Create a mock defaults object with only specific attributes
            # Using spec=[] means hasattr will return False for most attributes
            mock_defaults = MagicMock(
                spec=["approval_labels", "chatops_enabled", "chatops_required_permission"]
            )
            mock_defaults.approval_labels = ["custom-label"]
            mock_defaults.chatops_enabled = False
            mock_defaults.chatops_required_permission = "write"
    
            mock_settings.get.return_value = mock_defaults
            mock_settings.defaults = mock_defaults
    
>           defaults = RepoConfig._get_defaults()
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_config.py:129: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/config.py:229: in _get_defaults
    defaults[key] = getattr(settings_defaults, key)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='settings.get()' id='140613156095376'>
name = 'auto_approve_on_label'

    def __getattr__(self, name):
        if name in {'_mock_methods', '_mock_unsafe'}:
            raise AttributeError(name)
        elif self._mock_methods is not None:
            if name not in self._mock_methods or name in _all_magics:
>               raise AttributeError("Mock object has no attribute %r" % name)
E               AttributeError: Mock object has no attribute 'auto_approve_on_label'

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/unittest/mock.py:697: AttributeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_repo_config_get_defaults_with_settings_override - AttributeError: Mock object has no attribute 'auto_approve_on_label'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 9 passed, 3 deselected, 1 warning in 1.03s
operator: core/AddNot, occurrence: 14, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -251,7 +251,7 @@
 
         # Parse the repo-specific TOML
         repo_settings: dict[str, Any] = {}
-        if toml_content:
+        if not toml_content:
             try:
                 repo_settings = toml.loads(toml_content)
             except Exception as e:
F
=================================== FAILURES ===================================
__________________________ test_repo_config_from_toml __________________________

    def test_repo_config_from_toml():
        """Test parsing repository config from TOML."""
        toml_content = """
    approval_labels = ["test", "autoapprove"]
    auto_approve_on_label = true
    reapprove = true
    chatops_enabled = true
    chatops_required_permission = "write"
    approve_commands = ["approve", "stamp"]
    unapprove_commands = ["unapprove"]
    """
        config = RepoConfig.from_toml(toml_content)
>       assert "test" in config.approval_labels
E       AssertionError: assert 'test' in <BoxList: ['autoapprove', 'stamp']>
E        +  where <BoxList: ['autoapprove', 'stamp']> = <stampbot.config.RepoConfig object at 0x7faee93cfe00>.approval_labels

tests/test_config.py:22: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_repo_config_from_toml - AssertionError: assert 'test' in <BoxList: ['autoapprove', 'stamp']>
 +  where <BoxList: ['autoapprove', 'stamp']> = <stampbot.config.RepoConfig object at 0x7faee93cfe00>.approval_labels
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 3 deselected, 1 warning in 0.93s
operator: core/AddNot, occurrence: 15, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -263,7 +263,7 @@
         import re
 
         required_permission = merged.get("chatops_required_permission", "maintain")
-        if required_permission not in REPO_PERMISSION_LEVELS:
+        if not required_permission not in REPO_PERMISSION_LEVELS:
             raise ValueError(
                 "Invalid chatops_required_permission: "
                 f"{required_permission}. "
F
=================================== FAILURES ===================================
__________________________ test_repo_config_from_toml __________________________

    def test_repo_config_from_toml():
        """Test parsing repository config from TOML."""
        toml_content = """
    approval_labels = ["test", "autoapprove"]
    auto_approve_on_label = true
    reapprove = true
    chatops_enabled = true
    chatops_required_permission = "write"
    approve_commands = ["approve", "stamp"]
    unapprove_commands = ["unapprove"]
    """
>       config = RepoConfig.from_toml(toml_content)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_config.py:21: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cls = <class 'stampbot.config.RepoConfig'>
toml_content = '\napproval_labels = ["test", "autoapprove"]\nauto_approve_on_label = true\nreapprove = true\nchatops_enabled = true\nchatops_required_permission = "write"\napprove_commands = ["approve", "stamp"]\nunapprove_commands = ["unapprove"]\n'

    @classmethod
    def from_toml(cls, toml_content: str) -> RepoConfig:
        """Parse TOML content and merge with app defaults.
    
        Uses dynaconf to properly merge repo-specific settings with
        the app-level defaults, allowing repos to override only
        the settings they need to change.
    
        Args:
            toml_content: Raw TOML content from repo's stampbot.toml
    
        Returns:
            RepoConfig with merged settings
        """
        import toml
    
        # Start with defaults
        defaults = cls._get_defaults()
    
        # Parse the repo-specific TOML
        repo_settings: dict[str, Any] = {}
        if toml_content:
            try:
                repo_settings = toml.loads(toml_content)
            except Exception as e:
                raise ValueError(f"Invalid TOML content: {e}") from e
    
        # Merge: repo settings override defaults
        merged = {**defaults, **repo_settings}
    
        import re
    
        required_permission = merged.get("chatops_required_permission", "maintain")
        if not required_permission not in REPO_PERMISSION_LEVELS:
>           raise ValueError(
                "Invalid chatops_required_permission: "
                f"{required_permission}. "
                f"Valid values: {', '.join(REPO_PERMISSION_LEVELS)}"
            )
E           ValueError: Invalid chatops_required_permission: write. Valid values: none, read, triage, write, maintain, admin

stampbot/config.py:267: ValueError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_repo_config_from_toml - ValueError: Invalid chatops_required_permission: write. Valid values: none, read, triage, write, maintain, admin
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 3 deselected, 1 warning in 0.93s
operator: core/ReplaceTrueWithFalse, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -13,7 +13,7 @@
 # These can be overridden in settings.toml or per-repo stampbot.toml
 REPO_CONFIG_DEFAULTS = {
     "approval_labels": ["autoapprove", "stamp"],
-    "auto_approve_on_label": True,
+    "auto_approve_on_label": False,
     "reapprove": False,
     "chatops_enabled": True,
     "chatops_required_permission": "maintain",
.........F
=================================== FAILURES ===================================
_____________ test_repo_config_get_defaults_with_settings_override _____________

    def test_repo_config_get_defaults_with_settings_override():
        """Test _get_defaults respects settings.toml overrides."""
        with patch("stampbot.config.settings") as mock_settings:
            # Create a mock defaults object with only specific attributes
            # Using spec=[] means hasattr will return False for most attributes
            mock_defaults = MagicMock(
                spec=["approval_labels", "chatops_enabled", "chatops_required_permission"]
            )
            mock_defaults.approval_labels = ["custom-label"]
            mock_defaults.chatops_enabled = False
            mock_defaults.chatops_required_permission = "write"
    
            mock_settings.get.return_value = mock_defaults
            mock_settings.defaults = mock_defaults
    
            defaults = RepoConfig._get_defaults()
    
            # Should have the overridden values
            assert defaults["approval_labels"] == ["custom-label"]
            assert defaults["chatops_enabled"] is False
            assert defaults["chatops_required_permission"] == "write"
            # Non-overridden values should use REPO_CONFIG_DEFAULTS
>           assert defaults["auto_approve_on_label"] is True
E           assert False is True

tests/test_config.py:136: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_repo_config_get_defaults_with_settings_override - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 9 passed, 3 deselected, 1 warning in 0.94s
operator: core/ReplaceTrueWithFalse, occurrence: 1, definition_name: None
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -15,7 +15,7 @@
     "approval_labels": ["autoapprove", "stamp"],
     "auto_approve_on_label": True,
     "reapprove": False,
-    "chatops_enabled": True,
+    "chatops_enabled": False,
     "chatops_required_permission": "maintain",
     "approve_commands": ["approve", "stamp"],
     "unapprove_commands": ["unapprove", "unstamp"],
...........F
=================================== FAILURES ===================================
________________ test_repo_config_get_defaults_partial_override ________________

    def test_repo_config_get_defaults_partial_override():
        """Test _get_defaults with partial settings override."""
        with patch("stampbot.config.settings") as mock_settings:
            # Create a mock defaults object with only some attributes
            mock_defaults = MagicMock(spec=[])  # Empty spec means no attributes
            # But we can still check hasattr behavior by setting one attribute
            mock_defaults.approval_labels = ["override-only-this"]
    
            mock_settings.get.return_value = mock_defaults
            mock_settings.defaults = mock_defaults
    
            defaults = RepoConfig._get_defaults()
    
            # The overridden value
            assert defaults["approval_labels"] == ["override-only-this"]
            # Non-overridden values should use REPO_CONFIG_DEFAULTS
            assert defaults["auto_approve_on_label"] is True
>           assert defaults["chatops_enabled"] is True
E           assert False is True

tests/test_config.py:170: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_repo_config_get_defaults_partial_override - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 11 passed, 3 deselected, 1 warning in 0.95s
operator: core/ReplaceTrueWithFalse, occurrence: 2, definition_name: None
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -40,7 +40,7 @@
     envvar_prefix="STAMPBOT",
     settings_files=["settings.toml", ".secrets.toml"],
     environments=False,  # We don't use [development]/[production] sections
-    load_dotenv=True,
+    load_dotenv=False,
 )
 
 
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceTrueWithFalse, occurrence: 3, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -175,7 +175,7 @@
         if self.allowed_users or self.allowed_teams:
             # User is allowed if they're in allowed_users
             if pr_author in self.allowed_users:
-                return True, None
+                return False, None
 
             # Or if they're a member of an allowed team
             if self.allowed_teams and author_team_slugs:
.........................F
=================================== FAILURES ===================================
_______________________ test_is_pr_eligible_allowed_user _______________________

    def test_is_pr_eligible_allowed_user():
        """Test is_pr_eligible returns True when author is in allowed_users."""
        config = RepoConfig.from_toml('allowed_users = ["dependabot[bot]", "renovate[bot]"]')
        is_eligible, reason = config.is_pr_eligible([], "Update deps", "dependabot[bot]")
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:303: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_allowed_user - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 25 passed, 3 deselected, 1 warning in 0.95s
operator: core/ReplaceTrueWithFalse, occurrence: 4, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -183,7 +183,7 @@
                     # Support both "org/team" and "team" formats
                     team_slug = team.split("/")[-1] if "/" in team else team
                     if team_slug in author_team_slugs:
-                        return True, None
+                        return False, None
 
             # Neither user nor team matched
             if self.allowed_users and self.allowed_teams:
...........................F
=================================== FAILURES ===================================
_______________________ test_is_pr_eligible_allowed_team _______________________

    def test_is_pr_eligible_allowed_team():
        """Test is_pr_eligible returns True when author is in an allowed team."""
        config = RepoConfig.from_toml('allowed_teams = ["my-org/release-team"]')
        is_eligible, reason = config.is_pr_eligible(
            [], "Update deps", "team-member", author_team_slugs=["release-team"]
        )
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:321: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_allowed_team - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 27 passed, 3 deselected, 1 warning in 0.96s
operator: core/ReplaceTrueWithFalse, occurrence: 5, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -193,7 +193,7 @@
             else:
                 return False, "PR author not a member of any allowed team"
 
-        return True, None
+        return False, None
 
     def needs_team_check(self, pr_author: str) -> bool:
         """Check if team membership verification is needed for this author.
...............F
=================================== FAILURES ===================================
________________________ test_is_pr_eligible_no_filters ________________________

    def test_is_pr_eligible_no_filters():
        """Test is_pr_eligible returns True when no filters configured."""
        config = RepoConfig.default()
        is_eligible, reason = config.is_pr_eligible(["some-label"], "Some PR title", "someuser")
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:207: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_no_filters - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 15 passed, 3 deselected, 1 warning in 0.94s
operator: core/ReplaceTrueWithFalse, occurrence: 6, definition_name: needs_team_check
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -208,7 +208,7 @@
             return False
         if self.allowed_users and pr_author in self.allowed_users:
             return False
-        return True
+        return False
 
     @classmethod
     def _get_defaults(cls) -> dict[str, Any]:
...................................F
=================================== FAILURES ===================================
_______________ test_needs_team_check_user_not_in_allowed_users ________________

    def test_needs_team_check_user_not_in_allowed_users():
        """Test needs_team_check returns True when user not in allowed_users but teams configured."""
        toml_content = """
    allowed_users = ["special-user"]
    allowed_teams = ["my-org/release-team"]
    """
        config = RepoConfig.from_toml(toml_content)
>       assert config.needs_team_check("other-user") is True
E       AssertionError: assert False is True
E        +  where False = needs_team_check('other-user')
E        +    where needs_team_check = <stampbot.config.RepoConfig object at 0x7ffbd8d2b540>.needs_team_check

tests/test_config.py:413: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_needs_team_check_user_not_in_allowed_users - AssertionError: assert False is True
 +  where False = needs_team_check('other-user')
 +    where needs_team_check = <stampbot.config.RepoConfig object at 0x7ffbd8d2b540>.needs_team_check
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 35 passed, 3 deselected, 1 warning in 0.96s
operator: core/ReplaceTrueWithFalse, occurrence: 7, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -280,7 +280,7 @@
 
         return cls(
             approval_labels=merged.get("approval_labels", []),
-            auto_approve_on_label=merged.get("auto_approve_on_label", True),
+            auto_approve_on_label=merged.get("auto_approve_on_label", False),
             reapprove=merged.get("reapprove", False),
             chatops_enabled=merged.get("chatops_enabled", True),
             chatops_required_permission=required_permission,
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.22s
operator: core/ReplaceTrueWithFalse, occurrence: 8, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -282,7 +282,7 @@
             approval_labels=merged.get("approval_labels", []),
             auto_approve_on_label=merged.get("auto_approve_on_label", True),
             reapprove=merged.get("reapprove", False),
-            chatops_enabled=merged.get("chatops_enabled", True),
+            chatops_enabled=merged.get("chatops_enabled", False),
             chatops_required_permission=required_permission,
             approve_commands=merged.get("approve_commands", ["approve", "stamp"]),
             unapprove_commands=merged.get("unapprove_commands", ["unapprove", "unstamp"]),
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceFalseWithTrue, occurrence: 0, definition_name: None
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -14,7 +14,7 @@
 REPO_CONFIG_DEFAULTS = {
     "approval_labels": ["autoapprove", "stamp"],
     "auto_approve_on_label": True,
-    "reapprove": False,
+    "reapprove": True,
     "chatops_enabled": True,
     "chatops_required_permission": "maintain",
     "approve_commands": ["approve", "stamp"],
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.25s
operator: core/ReplaceFalseWithTrue, occurrence: 1, definition_name: None
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -39,7 +39,7 @@
 settings = Dynaconf(
     envvar_prefix="STAMPBOT",
     settings_files=["settings.toml", ".secrets.toml"],
-    environments=False,  # We don't use [development]/[production] sections
+    environments=True,  # We don't use [development]/[production] sections
     load_dotenv=True,
 )
 
........................................................................ [ 30%]
...........................F
=================================== FAILURES ===================================
__________________ test_lifespan_startup_shutdown_configured ___________________

    def test_lifespan_startup_shutdown_configured():
        """Test app lifespan startup and shutdown when configured."""
>       from stampbot.main import app

tests/test_main.py:15: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stampbot/main.py:46: in <module>
    configure_logging()
stampbot/logger.py:58: in configure_logging
    log_level_int = logging.getLevelName(settings.log_level)
                                         ^^^^^^^^^^^^^^^^^^
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/dynaconf/base.py:144: in __getattr__
    value = getattr(self._wrapped, name)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <dynaconf.base.Settings object at 0x7fbdae3f2f90>, name = 'LOG_LEVEL'

    def __getattribute__(self, name):
        if (
            name.startswith("__")
            or name in RESERVED_ATTRS + UPPER_DEFAULT_SETTINGS
        ):
            return super().__getattribute__(name)
    
        # This is to keep the only upper case mode working
        # self._store has Lazy values already evaluated
        if (
            name.islower()
            and self._store.get("LOWERCASE_READ_FOR_DYNACONF", empty) is False
        ):
            try:
                # only matches exact casing, first levels always upper
                return self._store.__getattribute__(name)
            except KeyError:
                return super().__getattribute__(name)
    
        # then go to the regular .get which triggers hooks among other things
        value = self.get(name, default=empty)
        if value is empty:
>           return super().__getattribute__(name)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           AttributeError: 'Settings' object has no attribute 'LOG_LEVEL'

../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/dynaconf/base.py:332: AttributeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_main.py::test_lifespan_startup_shutdown_configured - AttributeError: 'Settings' object has no attribute 'LOG_LEVEL'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 99 passed, 3 deselected, 1 warning in 2.25s
operator: core/ReplaceFalseWithTrue, occurrence: 2, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -162,7 +162,7 @@
         if self.required_labels:
             if not any(label in self.required_labels for label in pr_labels):
                 return (
-                    False,
+                    True,
                     f"PR missing required label (one of: {', '.join(self.required_labels)})",
                 )
 
.................F
=================================== FAILURES ===================================
__________________ test_is_pr_eligible_required_label_missing __________________

    def test_is_pr_eligible_required_label_missing():
        """Test is_pr_eligible returns False when required label is missing."""
        config = RepoConfig.from_toml('required_labels = ["dependencies", "automated"]')
        is_eligible, reason = config.is_pr_eligible(["other-label"], "PR title", "someuser")
>       assert is_eligible is False
E       assert True is False

tests/test_config.py:223: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_required_label_missing - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 17 passed, 3 deselected, 1 warning in 0.93s
operator: core/ReplaceFalseWithTrue, occurrence: 3, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -169,7 +169,7 @@
         # Check required title patterns filter
         if self.required_title_patterns:
             if not any(re.search(pattern, pr_title) for pattern in self.required_title_patterns):
-                return False, "PR title does not match any required pattern"
+                return True, "PR title does not match any required pattern"
 
         # Check allowed users/teams filter (if either is configured)
         if self.allowed_users or self.allowed_teams:
....................F
=================================== FAILURES ===================================
__________________ test_is_pr_eligible_title_pattern_no_match __________________

    def test_is_pr_eligible_title_pattern_no_match():
        """Test is_pr_eligible returns False when title doesn't match any pattern."""
        config = RepoConfig.from_toml('required_title_patterns = ["^chore:", "^\\\\[bot\\\\]"]')
        is_eligible, reason = config.is_pr_eligible([], "feat: add new feature", "someuser")
>       assert is_eligible is False
E       assert True is False

tests/test_config.py:248: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_title_pattern_no_match - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 20 passed, 3 deselected, 1 warning in 0.96s
operator: core/ReplaceFalseWithTrue, occurrence: 4, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -187,7 +187,7 @@
 
             # Neither user nor team matched
             if self.allowed_users and self.allowed_teams:
-                return False, "PR author not in allowed users or teams"
+                return True, "PR author not in allowed users or teams"
             elif self.allowed_users:
                 return False, f"PR author not in allowed users: {', '.join(self.allowed_users)}"
             else:
..............................F
=================================== FAILURES ===================================
__________________ test_is_pr_eligible_neither_user_nor_team ___________________

    def test_is_pr_eligible_neither_user_nor_team():
        """Test is_pr_eligible returns False when neither user nor team matches."""
        toml_content = """
    allowed_users = ["special-user"]
    allowed_teams = ["my-org/release-team"]
    """
        config = RepoConfig.from_toml(toml_content)
        is_eligible, reason = config.is_pr_eligible(
            [], "Update deps", "random-user", author_team_slugs=["other-team"]
        )
>       assert is_eligible is False
E       assert True is False

tests/test_config.py:358: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_neither_user_nor_team - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 30 passed, 3 deselected, 1 warning in 0.98s
operator: core/ReplaceFalseWithTrue, occurrence: 5, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -189,7 +189,7 @@
             if self.allowed_users and self.allowed_teams:
                 return False, "PR author not in allowed users or teams"
             elif self.allowed_users:
-                return False, f"PR author not in allowed users: {', '.join(self.allowed_users)}"
+                return True, f"PR author not in allowed users: {', '.join(self.allowed_users)}"
             else:
                 return False, "PR author not a member of any allowed team"
 
..........................F
=================================== FAILURES ===================================
_____________________ test_is_pr_eligible_user_not_allowed _____________________

    def test_is_pr_eligible_user_not_allowed():
        """Test is_pr_eligible returns False when author is not in allowed_users."""
        config = RepoConfig.from_toml('allowed_users = ["dependabot[bot]", "renovate[bot]"]')
        is_eligible, reason = config.is_pr_eligible([], "Update deps", "random-user")
>       assert is_eligible is False
E       assert True is False

tests/test_config.py:311: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_user_not_allowed - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 26 passed, 3 deselected, 1 warning in 0.96s
operator: core/ReplaceFalseWithTrue, occurrence: 6, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -191,7 +191,7 @@
             elif self.allowed_users:
                 return False, f"PR author not in allowed users: {', '.join(self.allowed_users)}"
             else:
-                return False, "PR author not a member of any allowed team"
+                return True, "PR author not a member of any allowed team"
 
         return True, None
 
............................F
=================================== FAILURES ===================================
_____________________ test_is_pr_eligible_team_not_matched _____________________

    def test_is_pr_eligible_team_not_matched():
        """Test is_pr_eligible returns False when author is not in any allowed team."""
        config = RepoConfig.from_toml('allowed_teams = ["my-org/release-team"]')
        is_eligible, reason = config.is_pr_eligible(
            [], "Update deps", "non-member", author_team_slugs=["other-team"]
        )
>       assert is_eligible is False
E       assert True is False

tests/test_config.py:331: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_team_not_matched - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 28 passed, 3 deselected, 1 warning in 0.95s
operator: core/ReplaceFalseWithTrue, occurrence: 7, definition_name: needs_team_check
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -205,7 +205,7 @@
             True if team check is needed (author not in allowed_users but teams configured)
         """
         if not self.allowed_teams:
-            return False
+            return True
         if self.allowed_users and pr_author in self.allowed_users:
             return False
         return True
.................................F
=================================== FAILURES ===================================
__________________ test_needs_team_check_no_teams_configured ___________________

    def test_needs_team_check_no_teams_configured():
        """Test needs_team_check returns False when no teams configured."""
        config = RepoConfig.from_toml('allowed_users = ["some-user"]')
>       assert config.needs_team_check("any-user") is False
E       AssertionError: assert True is False
E        +  where True = needs_team_check('any-user')
E        +    where needs_team_check = <stampbot.config.RepoConfig object at 0x7f423e773120>.needs_team_check

tests/test_config.py:393: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_needs_team_check_no_teams_configured - AssertionError: assert True is False
 +  where True = needs_team_check('any-user')
 +    where needs_team_check = <stampbot.config.RepoConfig object at 0x7f423e773120>.needs_team_check
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 33 passed, 3 deselected, 1 warning in 0.96s
operator: core/ReplaceFalseWithTrue, occurrence: 8, definition_name: needs_team_check
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -207,7 +207,7 @@
         if not self.allowed_teams:
             return False
         if self.allowed_users and pr_author in self.allowed_users:
-            return False
+            return True
         return True
 
     @classmethod
..................................F
=================================== FAILURES ===================================
_________________ test_needs_team_check_user_in_allowed_users __________________

    def test_needs_team_check_user_in_allowed_users():
        """Test needs_team_check returns False when user is in allowed_users."""
        toml_content = """
    allowed_users = ["special-user"]
    allowed_teams = ["my-org/release-team"]
    """
        config = RepoConfig.from_toml(toml_content)
>       assert config.needs_team_check("special-user") is False
E       AssertionError: assert True is False
E        +  where True = needs_team_check('special-user')
E        +    where needs_team_check = <stampbot.config.RepoConfig object at 0x7f641c483330>.needs_team_check

tests/test_config.py:403: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_needs_team_check_user_in_allowed_users - AssertionError: assert True is False
 +  where True = needs_team_check('special-user')
 +    where needs_team_check = <stampbot.config.RepoConfig object at 0x7f641c483330>.needs_team_check
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 34 passed, 3 deselected, 1 warning in 0.97s
operator: core/ReplaceFalseWithTrue, occurrence: 9, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -281,7 +281,7 @@
         return cls(
             approval_labels=merged.get("approval_labels", []),
             auto_approve_on_label=merged.get("auto_approve_on_label", True),
-            reapprove=merged.get("reapprove", False),
+            reapprove=merged.get("reapprove", True),
             chatops_enabled=merged.get("chatops_enabled", True),
             chatops_required_permission=required_permission,
             approve_commands=merged.get("approve_commands", ["approve", "stamp"]),
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.24s
operator: core/ReplaceAndWithOr, occurrence: 0, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -178,7 +178,7 @@
                 return True, None
 
             # Or if they're a member of an allowed team
-            if self.allowed_teams and author_team_slugs:
+            if self.allowed_teams or author_team_slugs:
                 for team in self.allowed_teams:
                     # Support both "org/team" and "team" formats
                     team_slug = team.split("/")[-1] if "/" in team else team
........................................................................ [ 30%]
........................................................................ [ 60%]
........................................................................ [ 91%]
.....................                                                    [100%]
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
237 passed, 3 deselected, 1 warning in 3.23s
operator: core/ReplaceAndWithOr, occurrence: 1, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -186,7 +186,7 @@
                         return True, None
 
             # Neither user nor team matched
-            if self.allowed_users and self.allowed_teams:
+            if self.allowed_users or self.allowed_teams:
                 return False, "PR author not in allowed users or teams"
             elif self.allowed_users:
                 return False, f"PR author not in allowed users: {', '.join(self.allowed_users)}"
............................F
=================================== FAILURES ===================================
_____________________ test_is_pr_eligible_team_not_matched _____________________

    def test_is_pr_eligible_team_not_matched():
        """Test is_pr_eligible returns False when author is not in any allowed team."""
        config = RepoConfig.from_toml('allowed_teams = ["my-org/release-team"]')
        is_eligible, reason = config.is_pr_eligible(
            [], "Update deps", "non-member", author_team_slugs=["other-team"]
        )
        assert is_eligible is False
>       assert "not a member of any allowed team" in reason
E       AssertionError: assert 'not a member of any allowed team' in 'PR author not in allowed users or teams'

tests/test_config.py:332: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_team_not_matched - AssertionError: assert 'not a member of any allowed team' in 'PR author not in allowed users or teams'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 28 passed, 3 deselected, 1 warning in 0.97s
operator: core/ReplaceAndWithOr, occurrence: 2, definition_name: needs_team_check
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -206,7 +206,7 @@
         """
         if not self.allowed_teams:
             return False
-        if self.allowed_users and pr_author in self.allowed_users:
+        if self.allowed_users or pr_author in self.allowed_users:
             return False
         return True
 
...................................F
=================================== FAILURES ===================================
_______________ test_needs_team_check_user_not_in_allowed_users ________________

    def test_needs_team_check_user_not_in_allowed_users():
        """Test needs_team_check returns True when user not in allowed_users but teams configured."""
        toml_content = """
    allowed_users = ["special-user"]
    allowed_teams = ["my-org/release-team"]
    """
        config = RepoConfig.from_toml(toml_content)
>       assert config.needs_team_check("other-user") is True
E       AssertionError: assert False is True
E        +  where False = needs_team_check('other-user')
E        +    where needs_team_check = <stampbot.config.RepoConfig object at 0x7fc549b4b540>.needs_team_check

tests/test_config.py:413: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_needs_team_check_user_not_in_allowed_users - AssertionError: assert False is True
 +  where False = needs_team_check('other-user')
 +    where needs_team_check = <stampbot.config.RepoConfig object at 0x7fc549b4b540>.needs_team_check
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 35 passed, 3 deselected, 1 warning in 0.97s
operator: core/ReplaceOrWithAnd, occurrence: 0, definition_name: __init__
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -117,7 +117,7 @@
         self.chatops_required_permission = chatops_required_permission
         self.approve_commands = approve_commands
         self.unapprove_commands = unapprove_commands
-        self.required_labels = required_labels or []
+        self.required_labels = required_labels and []
         self.required_title_patterns = required_title_patterns or []
         self.allowed_users = allowed_users or []
         self.allowed_teams = allowed_teams or []
............F
=================================== FAILURES ===================================
____________________ test_repo_config_with_required_labels _____________________

    def test_repo_config_with_required_labels():
        """Test parsing repository config with required labels."""
        toml_content = """
    required_labels = ["dependencies", "automated"]
    """
        config = RepoConfig.from_toml(toml_content)
>       assert config.required_labels == ["dependencies", "automated"]
E       AssertionError: assert [] == ['dependencies', 'automated']
E         
E         Right contains 2 more items, first extra item: 'dependencies'
E         
E         Full diff:
E         + []
E         - [
E         -     'dependencies',
E         -     'automated',
E         - ]

tests/test_config.py:180: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_repo_config_with_required_labels - AssertionError: assert [] == ['dependencies', 'automated']
  
  Right contains 2 more items, first extra item: 'dependencies'
  
  Full diff:
  + []
  - [
  -     'dependencies',
  -     'automated',
  - ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 12 passed, 3 deselected, 1 warning in 0.93s
operator: core/ReplaceOrWithAnd, occurrence: 1, definition_name: __init__
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -118,7 +118,7 @@
         self.approve_commands = approve_commands
         self.unapprove_commands = unapprove_commands
         self.required_labels = required_labels or []
-        self.required_title_patterns = required_title_patterns or []
+        self.required_title_patterns = required_title_patterns and []
         self.allowed_users = allowed_users or []
         self.allowed_teams = allowed_teams or []
         self.config_error = config_error
.............F
=================================== FAILURES ===================================
________________ test_repo_config_with_required_title_patterns _________________

    def test_repo_config_with_required_title_patterns():
        """Test parsing repository config with required title patterns."""
        toml_content = """
    required_title_patterns = ["^\\\\[bot\\\\]", "^chore:"]
    """
        config = RepoConfig.from_toml(toml_content)
>       assert len(config.required_title_patterns) == 2
E       assert 0 == 2
E        +  where 0 = len([])
E        +    where [] = <stampbot.config.RepoConfig object at 0x7fe04b419a70>.required_title_patterns

tests/test_config.py:189: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_repo_config_with_required_title_patterns - assert 0 == 2
 +  where 0 = len([])
 +    where [] = <stampbot.config.RepoConfig object at 0x7fe04b419a70>.required_title_patterns
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 13 passed, 3 deselected, 1 warning in 0.94s
operator: core/ReplaceOrWithAnd, occurrence: 2, definition_name: __init__
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -119,7 +119,7 @@
         self.unapprove_commands = unapprove_commands
         self.required_labels = required_labels or []
         self.required_title_patterns = required_title_patterns or []
-        self.allowed_users = allowed_users or []
+        self.allowed_users = allowed_users and []
         self.allowed_teams = allowed_teams or []
         self.config_error = config_error
 
..........................F
=================================== FAILURES ===================================
_____________________ test_is_pr_eligible_user_not_allowed _____________________

    def test_is_pr_eligible_user_not_allowed():
        """Test is_pr_eligible returns False when author is not in allowed_users."""
        config = RepoConfig.from_toml('allowed_users = ["dependabot[bot]", "renovate[bot]"]')
        is_eligible, reason = config.is_pr_eligible([], "Update deps", "random-user")
>       assert is_eligible is False
E       assert True is False

tests/test_config.py:311: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_user_not_allowed - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 26 passed, 3 deselected, 1 warning in 0.95s
operator: core/ReplaceOrWithAnd, occurrence: 3, definition_name: __init__
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -120,7 +120,7 @@
         self.required_labels = required_labels or []
         self.required_title_patterns = required_title_patterns or []
         self.allowed_users = allowed_users or []
-        self.allowed_teams = allowed_teams or []
+        self.allowed_teams = allowed_teams and []
         self.config_error = config_error
 
     def with_config_error(self, message: str) -> RepoConfig:
............................F
=================================== FAILURES ===================================
_____________________ test_is_pr_eligible_team_not_matched _____________________

    def test_is_pr_eligible_team_not_matched():
        """Test is_pr_eligible returns False when author is not in any allowed team."""
        config = RepoConfig.from_toml('allowed_teams = ["my-org/release-team"]')
        is_eligible, reason = config.is_pr_eligible(
            [], "Update deps", "non-member", author_team_slugs=["other-team"]
        )
>       assert is_eligible is False
E       assert True is False

tests/test_config.py:331: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_team_not_matched - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 28 passed, 3 deselected, 1 warning in 0.95s
operator: core/ReplaceOrWithAnd, occurrence: 4, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -172,7 +172,7 @@
                 return False, "PR title does not match any required pattern"
 
         # Check allowed users/teams filter (if either is configured)
-        if self.allowed_users or self.allowed_teams:
+        if self.allowed_users and self.allowed_teams:
             # User is allowed if they're in allowed_users
             if pr_author in self.allowed_users:
                 return True, None
..........................F
=================================== FAILURES ===================================
_____________________ test_is_pr_eligible_user_not_allowed _____________________

    def test_is_pr_eligible_user_not_allowed():
        """Test is_pr_eligible returns False when author is not in allowed_users."""
        config = RepoConfig.from_toml('allowed_users = ["dependabot[bot]", "renovate[bot]"]')
        is_eligible, reason = config.is_pr_eligible([], "Update deps", "random-user")
>       assert is_eligible is False
E       assert True is False

tests/test_config.py:311: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_user_not_allowed - assert True is False
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 26 passed, 3 deselected, 1 warning in 0.96s
operator: core/ExceptionReplacer, occurrence: 0, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -254,7 +254,7 @@
         if toml_content:
             try:
                 repo_settings = toml.loads(toml_content)
-            except Exception as e:
+            except CosmicRayTestingException as e:
                 raise ValueError(f"Invalid TOML content: {e}") from e
 
         # Merge: repo settings override defaults
.......F
=================================== FAILURES ===================================
___________________ test_repo_config_from_toml_parser_error ____________________

cls = <class 'stampbot.config.RepoConfig'>, toml_content = ';\r'

    @classmethod
    def from_toml(cls, toml_content: str) -> RepoConfig:
        """Parse TOML content and merge with app defaults.
    
        Uses dynaconf to properly merge repo-specific settings with
        the app-level defaults, allowing repos to override only
        the settings they need to change.
    
        Args:
            toml_content: Raw TOML content from repo's stampbot.toml
    
        Returns:
            RepoConfig with merged settings
        """
        import toml
    
        # Start with defaults
        defaults = cls._get_defaults()
    
        # Parse the repo-specific TOML
        repo_settings: dict[str, Any] = {}
        if toml_content:
            try:
>               repo_settings = toml.loads(toml_content)
                                ^^^^^^^^^^^^^^^^^^^^^^^^

stampbot/config.py:256: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

s = ';\r', _dict = <class 'dict'>
decoder = <toml.decoder.TomlDecoder object at 0x7f9d1eaf9bd0>

    def loads(s, _dict=dict, decoder=None):
        """Parses string as toml
    
        Args:
            s: String to be parsed
            _dict: (optional) Specifies the class of the returned toml dictionary
    
        Returns:
            Parsed toml file represented as a dictionary
    
        Raises:
            TypeError: When a non-string is passed
            TomlDecodeError: Error while decoding toml
        """
    
        implicitgroups = []
        if decoder is None:
            decoder = TomlDecoder(_dict)
        retval = decoder.get_empty_table()
        currentlevel = retval
        if not isinstance(s, basestring):
            raise TypeError("Expecting something like a string")
    
        if not isinstance(s, unicode):
            s = s.decode('utf8')
    
        original = s
        sl = list(s)
        openarr = 0
        openstring = False
        openstrchar = ""
        multilinestr = False
        arrayoftables = False
        beginline = True
        keygroup = False
        dottedkey = False
        keyname = 0
        key = ''
        prev_key = ''
        line_no = 1
    
        for i, item in enumerate(sl):
>           if item == '\r' and sl[i + 1] == '\n':
                                ^^^^^^^^^
E           IndexError: list index out of range

../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/toml/decoder.py:207: IndexError

During handling of the above exception, another exception occurred:

    def test_repo_config_from_toml_parser_error():
        """Test parser errors are normalized as config validation errors."""
        with pytest.raises(ValueError, match="Invalid TOML content"):
>           RepoConfig.from_toml(";\r")

tests/test_config.py:104: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cls = <class 'stampbot.config.RepoConfig'>, toml_content = ';\r'

    @classmethod
    def from_toml(cls, toml_content: str) -> RepoConfig:
        """Parse TOML content and merge with app defaults.
    
        Uses dynaconf to properly merge repo-specific settings with
        the app-level defaults, allowing repos to override only
        the settings they need to change.
    
        Args:
            toml_content: Raw TOML content from repo's stampbot.toml
    
        Returns:
            RepoConfig with merged settings
        """
        import toml
    
        # Start with defaults
        defaults = cls._get_defaults()
    
        # Parse the repo-specific TOML
        repo_settings: dict[str, Any] = {}
        if toml_content:
            try:
                repo_settings = toml.loads(toml_content)
>           except CosmicRayTestingException as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'CosmicRayTestingException' is not defined

stampbot/config.py:257: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_repo_config_from_toml_parser_error - NameError: name 'CosmicRayTestingException' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 7 passed, 3 deselected, 1 warning in 1.00s
operator: core/ExceptionReplacer, occurrence: 1, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -275,7 +275,7 @@
         for pattern in title_patterns:
             try:
                 re.compile(pattern)
-            except re.error as e:
+            except reCosmicRayTestingExceptionerror as e:
                 raise ValueError(f"Invalid regex pattern '{pattern}': {e}") from e
 
         return cls(
..............F
=================================== FAILURES ===================================
____________________ test_repo_config_invalid_regex_pattern ____________________

cls = <class 'stampbot.config.RepoConfig'>
toml_content = '\nrequired_title_patterns = ["[invalid"]\n'

    @classmethod
    def from_toml(cls, toml_content: str) -> RepoConfig:
        """Parse TOML content and merge with app defaults.
    
        Uses dynaconf to properly merge repo-specific settings with
        the app-level defaults, allowing repos to override only
        the settings they need to change.
    
        Args:
            toml_content: Raw TOML content from repo's stampbot.toml
    
        Returns:
            RepoConfig with merged settings
        """
        import toml
    
        # Start with defaults
        defaults = cls._get_defaults()
    
        # Parse the repo-specific TOML
        repo_settings: dict[str, Any] = {}
        if toml_content:
            try:
                repo_settings = toml.loads(toml_content)
            except Exception as e:
                raise ValueError(f"Invalid TOML content: {e}") from e
    
        # Merge: repo settings override defaults
        merged = {**defaults, **repo_settings}
    
        import re
    
        required_permission = merged.get("chatops_required_permission", "maintain")
        if required_permission not in REPO_PERMISSION_LEVELS:
            raise ValueError(
                "Invalid chatops_required_permission: "
                f"{required_permission}. "
                f"Valid values: {', '.join(REPO_PERMISSION_LEVELS)}"
            )
    
        # Validate regex patterns
        title_patterns = merged.get("required_title_patterns", [])
        for pattern in title_patterns:
            try:
>               re.compile(pattern)

stampbot/config.py:277: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/re/__init__.py:289: in compile
    return _compile(pattern, flags)
           ^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/re/__init__.py:350: in _compile
    p = _compiler.compile(pattern, flags)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/re/_compiler.py:762: in compile
    p = _parser.parse(p, flags)
        ^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/re/_parser.py:973: in parse
    p = _parse_sub(source, state, flags & SRE_FLAG_VERBOSE, 0)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/re/_parser.py:460: in _parse_sub
    itemsappend(_parse(source, state, verbose, nested + 1,
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

source = <re._parser.Tokenizer object at 0x7fe7500e3d90>
state = <re._parser.State object at 0x7fe74fd4ded0>, verbose = 0, nested = 1
first = True

    def _parse(source, state, verbose, nested, first=False):
        # parse a simple pattern
        subpattern = SubPattern(state)
    
        # precompute constants into local variables
        subpatternappend = subpattern.append
        sourceget = source.get
        sourcematch = source.match
        _len = len
        _ord = ord
    
        while True:
    
            this = source.next
            if this is None:
                break # end of pattern
            if this in "|)":
                break # end of subpattern
            sourceget()
    
            if verbose:
                # skip whitespace and comments
                if this in WHITESPACE:
                    continue
                if this == "#":
                    while True:
                        this = sourceget()
                        if this is None or this == "\n":
                            break
                    continue
    
            if this[0] == "\\":
                code = _escape(source, this, state)
                subpatternappend(code)
    
            elif this not in SPECIAL_CHARS:
                subpatternappend((LITERAL, _ord(this)))
    
            elif this == "[":
                here = source.tell() - 1
                # character set
                set = []
                setappend = set.append
    ##          if sourcematch(":"):
    ##              pass # handle character classes
                if source.next == '[':
                    import warnings
                    warnings.warn(
                        'Possible nested set at position %d' % source.tell(),
                        FutureWarning, stacklevel=nested + 6
                    )
                negate = sourcematch("^")
                # check remaining characters
                while True:
                    this = sourceget()
                    if this is None:
>                       raise source.error("unterminated character set",
                                           source.tell() - here)
E                       re.PatternError: unterminated character set at position 0

/opt/hostedtoolcache/Python/3.14.6/x64/lib/python3.14/re/_parser.py:568: PatternError

During handling of the above exception, another exception occurred:

    def test_repo_config_invalid_regex_pattern():
        """Test invalid regex pattern raises a ValueError."""
        toml_content = """
    required_title_patterns = ["[invalid"]
    """
        with pytest.raises(ValueError, match="Invalid regex pattern"):
>           RepoConfig.from_toml(toml_content)

tests/test_config.py:200: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cls = <class 'stampbot.config.RepoConfig'>
toml_content = '\nrequired_title_patterns = ["[invalid"]\n'

    @classmethod
    def from_toml(cls, toml_content: str) -> RepoConfig:
        """Parse TOML content and merge with app defaults.
    
        Uses dynaconf to properly merge repo-specific settings with
        the app-level defaults, allowing repos to override only
        the settings they need to change.
    
        Args:
            toml_content: Raw TOML content from repo's stampbot.toml
    
        Returns:
            RepoConfig with merged settings
        """
        import toml
    
        # Start with defaults
        defaults = cls._get_defaults()
    
        # Parse the repo-specific TOML
        repo_settings: dict[str, Any] = {}
        if toml_content:
            try:
                repo_settings = toml.loads(toml_content)
            except Exception as e:
                raise ValueError(f"Invalid TOML content: {e}") from e
    
        # Merge: repo settings override defaults
        merged = {**defaults, **repo_settings}
    
        import re
    
        required_permission = merged.get("chatops_required_permission", "maintain")
        if required_permission not in REPO_PERMISSION_LEVELS:
            raise ValueError(
                "Invalid chatops_required_permission: "
                f"{required_permission}. "
                f"Valid values: {', '.join(REPO_PERMISSION_LEVELS)}"
            )
    
        # Validate regex patterns
        title_patterns = merged.get("required_title_patterns", [])
        for pattern in title_patterns:
            try:
                re.compile(pattern)
>           except reCosmicRayTestingExceptionerror as e:
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           NameError: name 'reCosmicRayTestingExceptionerror' is not defined

stampbot/config.py:278: NameError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_repo_config_invalid_regex_pattern - NameError: name 'reCosmicRayTestingExceptionerror' is not defined
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 14 passed, 3 deselected, 1 warning in 1.11s
operator: core/NumberReplacer, occurrence: 0, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -181,7 +181,7 @@
             if self.allowed_teams and author_team_slugs:
                 for team in self.allowed_teams:
                     # Support both "org/team" and "team" formats
-                    team_slug = team.split("/")[-1] if "/" in team else team
+                    team_slug = team.split("/")[- 2] if "/" in team else team
                     if team_slug in author_team_slugs:
                         return True, None
 
...........................F
=================================== FAILURES ===================================
_______________________ test_is_pr_eligible_allowed_team _______________________

    def test_is_pr_eligible_allowed_team():
        """Test is_pr_eligible returns True when author is in an allowed team."""
        config = RepoConfig.from_toml('allowed_teams = ["my-org/release-team"]')
        is_eligible, reason = config.is_pr_eligible(
            [], "Update deps", "team-member", author_team_slugs=["release-team"]
        )
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:321: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_allowed_team - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 27 passed, 3 deselected, 1 warning in 0.96s
operator: core/NumberReplacer, occurrence: 1, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -181,7 +181,7 @@
             if self.allowed_teams and author_team_slugs:
                 for team in self.allowed_teams:
                     # Support both "org/team" and "team" formats
-                    team_slug = team.split("/")[-1] if "/" in team else team
+                    team_slug = team.split("/")[- 0] if "/" in team else team
                     if team_slug in author_team_slugs:
                         return True, None
 
...........................F
=================================== FAILURES ===================================
_______________________ test_is_pr_eligible_allowed_team _______________________

    def test_is_pr_eligible_allowed_team():
        """Test is_pr_eligible returns True when author is in an allowed team."""
        config = RepoConfig.from_toml('allowed_teams = ["my-org/release-team"]')
        is_eligible, reason = config.is_pr_eligible(
            [], "Update deps", "team-member", author_team_slugs=["release-team"]
        )
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:321: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_allowed_team - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 27 passed, 3 deselected, 1 warning in 0.95s
operator: core/RemoveDecorator, occurrence: 0, definition_name: RepoConfig
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -209,8 +209,6 @@
         if self.allowed_users and pr_author in self.allowed_users:
             return False
         return True
-
-    @classmethod
     def _get_defaults(cls) -> dict[str, Any]:
         """Get default repo config values.
 
F
=================================== FAILURES ===================================
__________________________ test_repo_config_from_toml __________________________

    def test_repo_config_from_toml():
        """Test parsing repository config from TOML."""
        toml_content = """
    approval_labels = ["test", "autoapprove"]
    auto_approve_on_label = true
    reapprove = true
    chatops_enabled = true
    chatops_required_permission = "write"
    approve_commands = ["approve", "stamp"]
    unapprove_commands = ["unapprove"]
    """
>       config = RepoConfig.from_toml(toml_content)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/test_config.py:21: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cls = <class 'stampbot.config.RepoConfig'>
toml_content = '\napproval_labels = ["test", "autoapprove"]\nauto_approve_on_label = true\nreapprove = true\nchatops_enabled = true\nchatops_required_permission = "write"\napprove_commands = ["approve", "stamp"]\nunapprove_commands = ["unapprove"]\n'

    @classmethod
    def from_toml(cls, toml_content: str) -> RepoConfig:
        """Parse TOML content and merge with app defaults.
    
        Uses dynaconf to properly merge repo-specific settings with
        the app-level defaults, allowing repos to override only
        the settings they need to change.
    
        Args:
            toml_content: Raw TOML content from repo's stampbot.toml
    
        Returns:
            RepoConfig with merged settings
        """
        import toml
    
        # Start with defaults
>       defaults = cls._get_defaults()
                   ^^^^^^^^^^^^^^^^^^^
E       TypeError: RepoConfig._get_defaults() missing 1 required positional argument: 'cls'

stampbot/config.py:248: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_repo_config_from_toml - TypeError: RepoConfig._get_defaults() missing 1 required positional argument: 'cls'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 3 deselected, 1 warning in 0.90s
operator: core/RemoveDecorator, occurrence: 1, definition_name: RepoConfig
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -229,8 +229,6 @@
                     defaults[key] = getattr(settings_defaults, key)
 
         return defaults
-
-    @classmethod
     def from_toml(cls, toml_content: str) -> RepoConfig:
         """Parse TOML content and merge with app defaults.
 
F
=================================== FAILURES ===================================
__________________________ test_repo_config_from_toml __________________________

    def test_repo_config_from_toml():
        """Test parsing repository config from TOML."""
        toml_content = """
    approval_labels = ["test", "autoapprove"]
    auto_approve_on_label = true
    reapprove = true
    chatops_enabled = true
    chatops_required_permission = "write"
    approve_commands = ["approve", "stamp"]
    unapprove_commands = ["unapprove"]
    """
>       config = RepoConfig.from_toml(toml_content)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       TypeError: RepoConfig.from_toml() missing 1 required positional argument: 'toml_content'

tests/test_config.py:21: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_repo_config_from_toml - TypeError: RepoConfig.from_toml() missing 1 required positional argument: 'toml_content'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 3 deselected, 1 warning in 0.90s
operator: core/RemoveDecorator, occurrence: 2, definition_name: RepoConfig
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -291,8 +291,6 @@
             allowed_users=merged.get("allowed_users", []),
             allowed_teams=merged.get("allowed_teams", []),
         )
-
-    @classmethod
     def default(cls) -> RepoConfig:
         """Return default configuration from app settings.
 
.F
=================================== FAILURES ===================================
___________________________ test_repo_config_default ___________________________

    def test_repo_config_default():
        """Test default repository config."""
>       config = RepoConfig.default()
                 ^^^^^^^^^^^^^^^^^^^^
E       TypeError: RepoConfig.default() missing 1 required positional argument: 'cls'

tests/test_config.py:34: TypeError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_repo_config_default - TypeError: RepoConfig.default() missing 1 required positional argument: 'cls'
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 1 passed, 3 deselected, 1 warning in 0.92s
operator: core/ZeroIterationForLoop, occurrence: 0, definition_name: is_pr_eligible
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -179,7 +179,7 @@
 
             # Or if they're a member of an allowed team
             if self.allowed_teams and author_team_slugs:
-                for team in self.allowed_teams:
+                for team in []:
                     # Support both "org/team" and "team" formats
                     team_slug = team.split("/")[-1] if "/" in team else team
                     if team_slug in author_team_slugs:
...........................F
=================================== FAILURES ===================================
_______________________ test_is_pr_eligible_allowed_team _______________________

    def test_is_pr_eligible_allowed_team():
        """Test is_pr_eligible returns True when author is in an allowed team."""
        config = RepoConfig.from_toml('allowed_teams = ["my-org/release-team"]')
        is_eligible, reason = config.is_pr_eligible(
            [], "Update deps", "team-member", author_team_slugs=["release-team"]
        )
>       assert is_eligible is True
E       assert False is True

tests/test_config.py:321: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_is_pr_eligible_allowed_team - assert False is True
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 27 passed, 3 deselected, 1 warning in 0.94s
operator: core/ZeroIterationForLoop, occurrence: 1, definition_name: _get_defaults
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -224,7 +224,7 @@
         # Allow overriding defaults via settings.toml [defaults] section
         if settings.get("defaults"):
             settings_defaults = settings.defaults
-            for key in defaults:
+            for key in []:
                 if hasattr(settings_defaults, key):
                     defaults[key] = getattr(settings_defaults, key)
 
.........F
=================================== FAILURES ===================================
_____________ test_repo_config_get_defaults_with_settings_override _____________

    def test_repo_config_get_defaults_with_settings_override():
        """Test _get_defaults respects settings.toml overrides."""
        with patch("stampbot.config.settings") as mock_settings:
            # Create a mock defaults object with only specific attributes
            # Using spec=[] means hasattr will return False for most attributes
            mock_defaults = MagicMock(
                spec=["approval_labels", "chatops_enabled", "chatops_required_permission"]
            )
            mock_defaults.approval_labels = ["custom-label"]
            mock_defaults.chatops_enabled = False
            mock_defaults.chatops_required_permission = "write"
    
            mock_settings.get.return_value = mock_defaults
            mock_settings.defaults = mock_defaults
    
            defaults = RepoConfig._get_defaults()
    
            # Should have the overridden values
>           assert defaults["approval_labels"] == ["custom-label"]
E           AssertionError: assert ['autoapprove', 'stamp'] == ['custom-label']
E             
E             At index 0 diff: 'autoapprove' != 'custom-label'
E             Left contains one more item: 'stamp'
E             
E             Full diff:
E               [
E             -     'custom-label',
E             +     'autoapprove',
E             +     'stamp',
E               ]

tests/test_config.py:132: AssertionError
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_repo_config_get_defaults_with_settings_override - AssertionError: assert ['autoapprove', 'stamp'] == ['custom-label']
  
  At index 0 diff: 'autoapprove' != 'custom-label'
  Left contains one more item: 'stamp'
  
  Full diff:
    [
  -     'custom-label',
  +     'autoapprove',
  +     'stamp',
    ]
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 9 passed, 3 deselected, 1 warning in 0.94s
operator: core/ZeroIterationForLoop, occurrence: 2, definition_name: from_toml
--- mutation diff ---
--- astampbot/config.py
+++ bstampbot/config.py
@@ -272,7 +272,7 @@
 
         # Validate regex patterns
         title_patterns = merged.get("required_title_patterns", [])
-        for pattern in title_patterns:
+        for pattern in []:
             try:
                 re.compile(pattern)
             except re.error as e:
..............F
=================================== FAILURES ===================================
____________________ test_repo_config_invalid_regex_pattern ____________________

    def test_repo_config_invalid_regex_pattern():
        """Test invalid regex pattern raises a ValueError."""
        toml_content = """
    required_title_patterns = ["[invalid"]
    """
>       with pytest.raises(ValueError, match="Invalid regex pattern"):
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       Failed: DID NOT RAISE <class 'ValueError'>

tests/test_config.py:199: Failed
=============================== warnings summary ===============================
../../../.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1
  /home/runner/.cache/pypoetry/virtualenvs/stampbot-q2WA0ezo-py3.14/lib/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
    from starlette.testclient import TestClient as TestClient  # noqa

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_config.py::test_repo_config_invalid_regex_pattern - Failed: DID NOT RAISE <class 'ValueError'>
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 14 passed, 3 deselected, 1 warning in 0.94s