From 220a97ab57c8eaef57c9324f395b41e68bc5470c Mon Sep 17 00:00:00 2001 From: michael Date: Thu, 12 Feb 2026 13:55:16 -0600 Subject: [PATCH] Wire up Errors tab in Auditing: auto-create ErrorItem on Analysis Error - Create ErrorItem record when proof analysis results in "Analysis Error" status - Add submitter_name/submitter_agency fields to ErrorItemResponse schema - Eager-load proof creator and agency in error items query to avoid N+1 - Populate submitter fields from proof creator in the API route - Update frontend ErrorItemResponse type and conversion to map submitter fields - Fix ErrorsTable proof name styling to blue link (text-active-blue) matching Flags tab Co-Authored-By: Claude Opus 4.6 --- backend/app/api/routes.py | 2 ++ backend/app/api/schemas.py | 2 ++ backend/app/repositories/audit_repository.py | 6 +++++- backend/app/websocket/handlers.py | 11 ++++++++++- frontend/components/Auditing.tsx | 2 +- frontend/services/apiService.ts | 6 ++++-- 6 files changed, 24 insertions(+), 5 deletions(-) diff --git a/backend/app/api/routes.py b/backend/app/api/routes.py index 98903df..728b39e 100755 --- a/backend/app/api/routes.py +++ b/backend/app/api/routes.py @@ -475,6 +475,8 @@ async def list_error_items( id=item.id, proof_version_id=item.proof_version_id, error_summary=item.error_summary, + submitter_name=item.proof_version.proof.created_by_user.name if item.proof_version and item.proof_version.proof and item.proof_version.proof.created_by_user else None, + submitter_agency=item.proof_version.proof.created_by_user.agency.name if item.proof_version and item.proof_version.proof and item.proof_version.proof.created_by_user and item.proof_version.proof.created_by_user.agency else None, campaign_name=item.proof_version.proof.campaign.name if item.proof_version and item.proof_version.proof and item.proof_version.proof.campaign else None, proof_name=item.proof_version.proof.proof_name if item.proof_version and item.proof_version.proof else None, version=item.proof_version.version if item.proof_version else None, diff --git a/backend/app/api/schemas.py b/backend/app/api/schemas.py index 9a96290..aa9897e 100755 --- a/backend/app/api/schemas.py +++ b/backend/app/api/schemas.py @@ -129,6 +129,8 @@ class ErrorItemResponse(BaseModel): id: uuid.UUID proof_version_id: uuid.UUID error_summary: Optional[str] + submitter_name: Optional[str] + submitter_agency: Optional[str] campaign_name: Optional[str] proof_name: Optional[str] version: Optional[int] diff --git a/backend/app/repositories/audit_repository.py b/backend/app/repositories/audit_repository.py index 2e8a48e..31fb799 100755 --- a/backend/app/repositories/audit_repository.py +++ b/backend/app/repositories/audit_repository.py @@ -5,7 +5,7 @@ from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload -from app.models.models import FlaggedItem, ResolvedItem, ErrorItem, ProofVersion, Proof, Campaign +from app.models.models import FlaggedItem, ResolvedItem, ErrorItem, ProofVersion, Proof, Campaign, User class AuditRepository: @@ -134,6 +134,10 @@ class AuditRepository: selectinload(ErrorItem.proof_version) .selectinload(ProofVersion.proof) .selectinload(Proof.campaign), + selectinload(ErrorItem.proof_version) + .selectinload(ProofVersion.proof) + .selectinload(Proof.created_by_user) + .selectinload(User.agency), ) .join(ProofVersion) .join(Proof) diff --git a/backend/app/websocket/handlers.py b/backend/app/websocket/handlers.py index 8464108..1d32f73 100755 --- a/backend/app/websocket/handlers.py +++ b/backend/app/websocket/handlers.py @@ -9,7 +9,7 @@ from app.websocket.manager import ConnectionManager from app.services.analysis_service import AnalysisService from app.models.schemas import SubReview from app.models.database import async_session_factory -from app.repositories import ProofRepository, CampaignRepository, UserRepository +from app.repositories import ProofRepository, CampaignRepository, UserRepository, AuditRepository from app.services.storage_service import storage_service logger = logging.getLogger(__name__) @@ -231,6 +231,15 @@ async def handle_analyze_message( is_identical_file=is_identical_file, ) + # Auto-create ErrorItem when analysis results in an error + if result.overallStatus == "Analysis Error": + audit_repo = AuditRepository(session) + await audit_repo.create_error_item( + proof_version_id=version.id, + error_summary=result.leadAgentSummary, + ) + logger.info(f"[WEBSOCKET] Created ErrorItem for analysis error on version {version.id}") + await session.commit() proof_id = str(proof.id) version_id = str(version.id) diff --git a/frontend/components/Auditing.tsx b/frontend/components/Auditing.tsx index 9a364fc..ff2ed2e 100755 --- a/frontend/components/Auditing.tsx +++ b/frontend/components/Auditing.tsx @@ -135,7 +135,7 @@ const ErrorsTable: React.FC<{ items: ErrorItem[], onNavigate: AuditingProps['onN onClick={() => onNavigate(item)} title={`Click to view Version ${item.version} of ${item.proofName}`} > - {item.proofName} + {item.proofName} Version {item.version} {item.submitter} {item.submitAgency} diff --git a/frontend/services/apiService.ts b/frontend/services/apiService.ts index 031762c..e27c8ff 100755 --- a/frontend/services/apiService.ts +++ b/frontend/services/apiService.ts @@ -81,6 +81,8 @@ export interface ErrorItemResponse { id: string; proof_version_id: string; error_summary: string | null; + submitter_name: string | null; + submitter_agency: string | null; campaign_name: string | null; proof_name: string | null; version: number | null; @@ -333,8 +335,8 @@ class ApiService { campaignName: item.campaign_name || '', proofName: item.proof_name || '', version: item.version || 1, - submitter: '', - submitAgency: '', + submitter: item.submitter_name || '', + submitAgency: item.submitter_agency || '', errorSummary: item.error_summary || '', timestamp: item.created_at, };