import { api, supplementalApi } from "../../lib/api"; import type { components } from "../../lib/api.gen"; type ApiSchema = components["schemas"][Name]; /** G5 wire DTO는 생성된 FastAPI OpenAPI 계약을 그대로 사용한다. */ export type CalibrationConfidenceInterval = ApiSchema<"ConfidenceInterval">; export type CalibrationPair = ApiSchema<"CalibrationPair">; export type CompetencyCalibrationAssessment = ApiSchema<"CompetencyCalibrationAssessment">; export type MetacognitivePrescription = ApiSchema<"MetacognitivePrescription">; export type PredictionRevisionItem = ApiSchema<"PredictionRevisionItem">; export type PredictionLockItem = ApiSchema<"PredictionLockItem">; export type PerformanceObservationItem = ApiSchema<"PerformanceObservationItem">; export type PredictionHistoryItem = ApiSchema<"PredictionHistoryItem">; export type CalibrationAssessmentItem = ApiSchema<"CalibrationAssessmentItem">; export type TransferAssessment = ApiSchema<"TransferAssessment">; export type TransferTrialItem = ApiSchema<"TransferTrialItem">; export type TransferAssessmentItem = ApiSchema<"TransferAssessmentItem">; export type SyntheticSubgroupResult = ApiSchema<"SyntheticSubgroupResult">; export type SubgroupDriftReport = ApiSchema<"SubgroupDriftReport">; export type DriftReportItem = ApiSchema<"DriftReportItem">; export type TransferSuiteItem = ApiSchema<"TransferSuiteItem">; export type TeacherReviewItem = ApiSchema<"TeacherReviewItem">; export type CalibrationTransferReadModelResponse = ApiSchema<"CalibrationTransferReadModelResponse">; export type PredictionRevisionRequest = ApiSchema<"PredictionRevisionRequest">; export type PredictionRevisionResponse = ApiSchema<"PredictionRevisionResponse">; export type PredictionLockRequest = ApiSchema<"PredictionLockRequest">; export type PredictionLockResponse = ApiSchema<"PredictionLockResponse">; export type TeacherCorrectionResponse = ApiSchema<"TeacherReviewResponse">; export type ActualTransferAssessment = ApiSchema<"ActualTransferAssessment">; export type ActualTransferExecutionRequest = ApiSchema<"ActualTransferExecutionRequest">; export type ActualTransferExecutionResponse = ApiSchema<"ActualTransferExecutionResponse">; export type CalibrationBias = CompetencyCalibrationAssessment["bias"]; export type CalibrationImprovement = CompetencyCalibrationAssessment["improvement"]; export type PerformanceStatus = PerformanceObservationItem["status"]; export type RelationshipStyle = TransferTrialItem["relationship_style"]; export type DriftStatus = SubgroupDriftReport["status"]; /** 교수자 UI는 원판정 쓰기를 열지 않고 append-only 교정만 허용한다. */ export type TeacherCorrectionRequest = Omit< ApiSchema<"TeacherReviewRequest">, "disposition" | "correction_payload" > & { disposition: "corrected"; correction_payload: { teacher_note: string }; }; interface TeacherSessionRef { session_id: string; learner_id: string; } interface TeacherDashboardLookup { pending_reviews?: TeacherSessionRef[]; recent_sessions?: TeacherSessionRef[]; } function learnerPath(learnerId?: string): string { return learnerId ? `/calibration/learners/${encodeURIComponent(learnerId)}` : "/calibration/learners/me"; } export class CalibrationLearnerContextError extends Error { constructor() { super("이 회기의 학습자 캘리브레이션 원장을 찾지 못했습니다."); this.name = "CalibrationLearnerContextError"; } } export const calibrationTransferApi = { getForLearner: (sessionId: string, signal?: AbortSignal) => supplementalApi.get( `${learnerPath()}?session_id=${encodeURIComponent(sessionId)}`, { signal }, ), getForTeacherSession: async (sessionId: string, signal?: AbortSignal) => { const dashboard = await supplementalApi.get( "/teacher/dashboard", { signal }, ); const session = [ ...(dashboard.pending_reviews ?? []), ...(dashboard.recent_sessions ?? []), ].find((item) => item.session_id === sessionId); if (!session) throw new CalibrationLearnerContextError(); return supplementalApi.get( learnerPath(session.learner_id), { signal }, ); }, appendPredictionRevision: (body: PredictionRevisionRequest) => api.post( "/calibration/predictions/revisions", body, ), lockPrediction: (historyId: string, body: PredictionLockRequest) => api.post( `/calibration/predictions/${encodeURIComponent(historyId)}/lock`, body, ), appendTeacherCorrection: (body: TeacherCorrectionRequest) => api.post("/calibration/reviews", body), appendActualTransferExecution: (body: ActualTransferExecutionRequest) => api.post( "/calibration/transfer-executions", body, ), };