/** * Protocol comparative analysis — the "מה קרה בדיון" panel (#226). * * `analyze_protocol` compares the ערר hearing protocol against the written * pleadings and records, per argument, whether it was strengthened, newly * raised, or dropped at the hearing — plus the sharpened legal question and a * verbatim evidence quote. This module exposes the read + trigger endpoints. */ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "./client"; import type { LegalArgumentParty } from "./legal-arguments"; export type ProtocolChangeType = "strengthened" | "newly_raised" | "dropped"; /** Empty string = an unassigned party_role on a verdict row. */ export type ProtocolPartyRole = LegalArgumentParty | ""; export type ProtocolAnalysisRow = { id: string; case_id: string; document_id: string; party_role: ProtocolPartyRole; change_type: ProtocolChangeType; /** The pleaded argument this verdict matched (strengthened/dropped); null for newly_raised. */ argument_id: string | null; argument_title: string; summary: string; sharpened_question: string; evidence_quote: string; page_number: number | null; created_at?: string; }; export type ProtocolHeader = { hearing_date: string | null; protocol_title: string; protocol_document_id: string; panel_members: string[]; appellants_present: string[]; respondents_present: string[]; }; export type ProtocolAnalysisResponse = { case_number: string; total: number; header: ProtocolHeader; by_change: Partial>; by_party: Partial>; analysis: ProtocolAnalysisRow[]; }; export const protocolAnalysisKeys = { all: ["protocol-analysis"] as const, byCase: (caseNumber: string) => [...protocolAnalysisKeys.all, caseNumber] as const, }; export function useProtocolAnalysis(caseNumber: string | undefined) { return useQuery({ queryKey: protocolAnalysisKeys.byCase(caseNumber ?? ""), queryFn: ({ signal }) => apiRequest( `/api/cases/${caseNumber}/protocol-analysis`, { signal }, ), enabled: Boolean(caseNumber), staleTime: 10_000, }); } /** * The analysis runs on the legal-analyst agent (host-side, where the `claude` * CLI lives) — NOT inline in the FastAPI container. The endpoint delegates via * a Paperclip wakeup (`queued`), or reports `skipped` when no analyst route is * available (the chair can then run the MCP tool manually). */ export type AnalyzeProtocolResult = | { status: "queued"; sub_issue_id: string; analyst_id: string; main_issue_id: string; } | { status: "skipped"; reason: "no_api_key" | "no_analyst" | "no_issue" | string; company_id?: string; }; export function useAnalyzeProtocol(caseNumber: string | undefined) { const qc = useQueryClient(); return useMutation({ mutationFn: (documentId?: string) => apiRequest( `/api/cases/${caseNumber}/analyze-protocol${ documentId ? `?document_id=${encodeURIComponent(documentId)}` : "" }`, { method: "POST" }, ), onSuccess: () => { if (caseNumber) { qc.invalidateQueries({ queryKey: protocolAnalysisKeys.byCase(caseNumber), }); } }, }); } export const CHANGE_LABELS_HE: Record = { strengthened: "התחזק בדיון", newly_raised: "נטען לראשונה", dropped: "נזנח בדיון", }; export const PROTOCOL_PARTY_LABELS_HE: Record = { appellant: "עוררים", respondent: "משיבים", committee: "ועדה מקומית", permit_applicant: "מבקשי היתר", unknown: "צד לא מזוהה", "": "צד לא מסווג", }; /** Display order for the per-party sections. */ export const PROTOCOL_PARTY_ORDER: ProtocolPartyRole[] = [ "appellant", "committee", "respondent", "permit_applicant", "unknown", "", ];