feat(psa): add spin-off ticket system prompt rule, backend routing tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-16 03:01:21 +00:00
parent 6e0188d0b4
commit 7fa81f69a6
2 changed files with 72 additions and 0 deletions

View File

@@ -154,6 +154,23 @@ To create a fork, append this marker AFTER your [QUESTIONS]/[ACTIONS] markers:
- If a question is clearly outside your domain, say so briefly and redirect.
- Never fabricate error codes, KB article numbers, or CLI flags. If unsure, say so.
## SPIN-OFF TICKET CREATION
When you identify a second distinct issue that is clearly separate from the primary topic \
of this session, suggest creating a spin-off ticket using the [ACTIONS] marker below. \
Use this sparingly — only when the issue is genuinely independent, not for every tangential mention.
Format:
[ACTIONS]
[
{
"label": "Create ticket: <brief issue title>",
"command": "create_spin_off_ticket",
"description": "<one sentence description of the separate issue>"
}
]
[/ACTIONS]
## FINAL REMINDER — THIS OVERRIDES EVERYTHING ABOVE
Every single response MUST contain [QUESTIONS] and/or [ACTIONS] markers with valid JSON. \
No exceptions. Not even when forking. A response without at least one of these markers \

View File

@@ -0,0 +1,55 @@
# backend/tests/test_psa_tickets.py
"""Routing and auth tests for new ticket management endpoints."""
import pytest
@pytest.mark.asyncio
async def test_create_ticket_requires_auth(client):
"""POST /tickets returns 401 without auth."""
response = await client.post(
"/api/v1/integrations/psa/tickets",
json={
"summary": "Test", "company_id": 1, "board_id": 1,
"status_id": 1, "priority_id": 1
},
)
assert response.status_code == 401
@pytest.mark.asyncio
async def test_list_resources_requires_auth(client):
response = await client.get("/api/v1/integrations/psa/tickets/1/resources")
assert response.status_code == 401
@pytest.mark.asyncio
async def test_search_tickets_returns_paginated_shape(client, auth_headers):
"""search endpoint returns TicketListResponse shape when no PSA connected."""
response = await client.get(
"/api/v1/integrations/psa/tickets/search",
headers=auth_headers,
)
# No PSA connection → 400 or 502; with PSA → 200
assert response.status_code in (200, 400, 502)
if response.status_code == 200:
data = response.json()
assert "items" in data
assert "total" in data
assert "page" in data
@pytest.mark.asyncio
async def test_update_status_requires_auth(client):
response = await client.patch(
"/api/v1/integrations/psa/tickets/1/status?status_id=5"
)
assert response.status_code == 401
@pytest.mark.asyncio
async def test_ai_parse_requires_auth(client):
response = await client.post(
"/api/v1/integrations/psa/tickets/ai-parse",
json={"prompt": "New ticket for Acme"},
)
assert response.status_code == 401