/** * Style-acquisition learning surface (T6/T13) — reconciliation ledger + style-distance. * Backs the /training "למידה" tab. Endpoints under /api/learning. */ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "./client"; export type DraftFinalPair = { id: string; case_id: string | null; case_number: string; title: string; status: "final_received" | "analyzed" | "lessons_folded" | string; change_percent: number | null; created_at: string | null; updated_at: string | null; }; export type StyleDistance = { case_number: string; outcome: string; golden_ratio_adherence: { outcome: string; total_words: number; sections: Record; max_deviation: number | null; }; anti_pattern_hits: { total: number; by_pattern: Record }; draft_to_final_diff: { change_percent?: number } | null; pair_status: string | null; summary: { ratio_max_deviation_pp: number | null; anti_pattern_total: number; change_percent: number | null; }; error?: string; }; export const learningKeys = { all: ["learning"] as const, pairs: (status: string) => [...learningKeys.all, "pairs", status] as const, distance: (caseNumber: string) => [...learningKeys.all, "distance", caseNumber] as const, }; export function useReconciliationLedger(status = "") { return useQuery({ queryKey: learningKeys.pairs(status), queryFn: ({ signal }) => apiRequest<{ items: DraftFinalPair[]; count: number }>( `/api/learning/pairs${status ? `?status=${status}` : ""}`, { signal }, ), staleTime: 15_000, }); } export function useStyleDistance(caseNumber: string | null) { return useQuery({ queryKey: learningKeys.distance(caseNumber ?? ""), queryFn: ({ signal }) => apiRequest( `/api/learning/style-distance/${encodeURIComponent(caseNumber!)}`, { signal }, ), enabled: Boolean(caseNumber), staleTime: 15_000, }); } // ── T14: curator distillation proposal + chair approval gate ────── export type DistillationChange = { type?: string; domain?: string; block?: string; description?: string; draft_text?: string; final_text?: string; lesson?: string; }; export type PairDetail = { id: string; case_number: string; title: string; status: string; diff_stats: { change_percent?: number } | null; overall_assessment: string; changes: DistillationChange[]; // style_method only (server-filtered) new_expressions: string[]; }; export function usePairDetail(pairId: string | null) { return useQuery({ queryKey: [...learningKeys.all, "pair", pairId ?? ""] as const, queryFn: ({ signal }) => apiRequest(`/api/learning/pairs/${pairId}`, { signal }), enabled: Boolean(pairId), staleTime: 15_000, }); } export function usePromoteLearning(pairId: string) { const qc = useQueryClient(); return useMutation({ mutationFn: (body: { lessons: string[]; phrases: string[] }) => apiRequest<{ id: string; status: string; folded_lessons: number; folded_phrases: number }>( `/api/learning/pairs/${pairId}/promote`, { method: "POST", body }, ), onSuccess: () => { qc.invalidateQueries({ queryKey: learningKeys.all }); }, }); }