import { z } from "zod"; import { REVIEW_CAPPING_ILF_LIMITS, calculateReviewLayerApplication, calibrateReviewIlf, applyReviewIlf, replayReviewLayerApplication, replayReviewIlfCalibration, replayReviewIlfApplication, validateReviewLayerApplicationRequest, validateReviewIlfCalibrationRequest, validateReviewIlfApplicationRequest, isDiagnosticPlainRecord, isDiagnosticToken, isRealIsoDate, type ReviewLayerApplicationRequest, type ReviewIlfCalibrationRequest, type ReviewIlfApplicationRequest, type ReviewLayerApplication, type ReviewIlfCalibration, type ReviewIlfApplication, } from "@actuarial-ts/core"; import { analysisMeasureDefinitionSchema, financialTermSchema, preparedHistoricalObservationSchema } from "./customizationContracts.js"; import { analysisContextSchema, analysisReferenceSchema, analysisSnapshotSchema, quantitySemanticsSchema, reviewAssumptionDefinitionSchema } from "./reviewContracts.js"; import { reviewOriginSeriesRequestSchema } from "./reviewOriginSeriesContracts.js"; import { parseReviewBoundary } from "./reviewBoundary.js"; const token = z.string().refine(isDiagnosticToken), date = z.string().refine(isRealIsoDate); const declaration = z.object({ actorId: token, knownDate: date, rationale: token }).strict(); const limits = z.object({ maximumObservations: z.number().int().positive().max(REVIEW_CAPPING_ILF_LIMITS.maximumObservations), maximumOrigins: z.number().int().positive().max(REVIEW_CAPPING_ILF_LIMITS.maximumOrigins), maximumInputCharacters: z.number().int().positive().max(REVIEW_CAPPING_ILF_LIMITS.maximumInputCharacters), maximumOutputCharacters: z.number().int().positive().max(REVIEW_CAPPING_ILF_LIMITS.maximumOutputCharacters), }).strict(); export const reviewLayerApplicationRequestSchema = z.object({ id: token, version: token, context: analysisContextSchema, quantity: quantitySemanticsSchema, observations: z.array(preparedHistoricalObservationSchema).min(1).max(REVIEW_CAPPING_ILF_LIMITS.maximumObservations), measureDefinitions: z.array(analysisMeasureDefinitionSchema).min(1), term: financialTermSchema, completeFinancialPopulation: z.literal(true), snapshots: z.array(analysisSnapshotSchema), declaration, limits, }).strict(); const retainedLayer = z.unknown().superRefine((value, context) => { const parsed = z.object({ request: reviewLayerApplicationRequestSchema }).passthrough().safeParse(value); if (!parsed.success) parsed.error.issues.forEach(issue => context.addIssue(issue)); }); const assumptionTemplate = reviewAssumptionDefinitionSchema.omit({ contractVersion: true, value: true, provenance: true }); export const reviewIlfCalibrationRequestSchema = z.object({ id: token, version: token, layer: retainedLayer, targetLimit: z.number().finite().positive().nullable(), method: z.discriminatedUnion("kind", [ z.object({ kind: z.literal("fitted"), distribution: z.enum(["lognormal", "pareto"]), openStatuses: z.array(token), sourceRelationship: z.enum(["current-data", "separate-data"]) }).strict(), z.object({ kind: z.literal("table"), table: z.array(z.object({ limit: z.number().finite().positive(), factor: z.number().finite().positive() }).strict()).min(2), sourceRelationship: z.literal("separate-data") }).strict(), ]), data: z.array(analysisReferenceSchema).min(1), snapshots: z.array(analysisSnapshotSchema), knowledgeDate: date, assumption: assumptionTemplate, limits, }).strict(); const retainedCalibration = z.unknown().superRefine((value, context) => { const parsed = z.object({ request: reviewIlfCalibrationRequestSchema }).passthrough().safeParse(value); if (!parsed.success) parsed.error.issues.forEach(issue => context.addIssue(issue)); }); const retainedSeries = z.unknown().superRefine((value, context) => { const parsed = z.object({ request: reviewOriginSeriesRequestSchema }).passthrough().safeParse(value); if (!parsed.success) parsed.error.issues.forEach(issue => context.addIssue(issue)); }); export const reviewIlfApplicationRequestSchema = z.object({ id: token, version: token, series: retainedSeries, calibration: retainedCalibration, targetFinancialBasis: analysisSnapshotSchema, snapshots: z.array(analysisSnapshotSchema), policies: z.object({ unavailable: z.enum(["retain-unavailable", "reject"]), unadoptedAssumption: z.enum(["reject", "allow-qualified"]) }).strict(), declaration, limits, }).strict(); export function parseReviewLayerApplicationRequest(input: unknown): ReviewLayerApplicationRequest { return validateReviewLayerApplicationRequest(parseReviewBoundary(reviewLayerApplicationRequestSchema, input) as ReviewLayerApplicationRequest).request; } export function parseReviewIlfCalibrationRequest(input: unknown): ReviewIlfCalibrationRequest { return validateReviewIlfCalibrationRequest(parseReviewBoundary(reviewIlfCalibrationRequestSchema, input) as ReviewIlfCalibrationRequest).request; } export function parseReviewIlfApplicationRequest(input: unknown): ReviewIlfApplicationRequest { return validateReviewIlfApplicationRequest(parseReviewBoundary(reviewIlfApplicationRequestSchema, input) as ReviewIlfApplicationRequest).request; } export function calculateReviewLayerApplicationFromInput(input: unknown): ReviewLayerApplication { return calculateReviewLayerApplication(parseReviewLayerApplicationRequest(input)); } export function calibrateReviewIlfFromInput(input: unknown): ReviewIlfCalibration { return calibrateReviewIlf(parseReviewIlfCalibrationRequest(input)); } export function applyReviewIlfFromInput(input: unknown): ReviewIlfApplication { return applyReviewIlf(parseReviewIlfApplicationRequest(input)); } export function replayReviewLayerApplicationFromInput(input: unknown): ReviewLayerApplication { return replayReviewLayerApplication(parseReviewBoundary(z.custom(isDiagnosticPlainRecord), input)); } export function replayReviewIlfCalibrationFromInput(input: unknown): ReviewIlfCalibration { return replayReviewIlfCalibration(parseReviewBoundary(z.custom(isDiagnosticPlainRecord), input)); } export function replayReviewIlfApplicationFromInput(input: unknown): ReviewIlfApplication { return replayReviewIlfApplication(parseReviewBoundary(z.custom(isDiagnosticPlainRecord), input)); }