import { z } from "zod"; /** * Lotse block of the report snapshot (client-safe, lane L9). Stored as optional `content.lotse` of * `ReportContent` (src/lib/reports/content.ts), so it is frozen together with the report on approval. * * Suggestions are kept SEPARATE from `content.texts`: nothing the model wrote reaches the report text * until a person accepts it (Spec §15.3/§15.4, Brandbook §12.4). `reviewedAt` is set on submit when * the submitter confirmed "Ich habe den Vorschlag geprüft" (checked server-side in submitReport). */ /** Report text fields the Lotse drafts (ReportDraftOutput); `problems` stays technician-only. */ export const LOTSE_TEXT_FIELDS = ["workPerformed", "deviations", "additionalWork", "openItems", "nextSteps", "hints"] as const; export type LotseTextField = (typeof LOTSE_TEXT_FIELDS)[number]; export const LOTSE_SUGGESTION_STATES = ["pending", "accepted", "discarded"] as const; export type LotseSuggestionState = (typeof LOTSE_SUGGESTION_STATES)[number]; export const LOTSE_TEXT_MAX = 10_000; export const LOTSE_MISSING_MAX = 20; const isoDateTime = z.string().datetime({ offset: true }); export const lotseSuggestionSchema = z.object({ field: z.enum(LOTSE_TEXT_FIELDS), text: z.string().max(LOTSE_TEXT_MAX), state: z.enum(LOTSE_SUGGESTION_STATES), decidedAt: isoDateTime.nullable(), }); export type LotseSuggestion = z.infer; export const lotseBlockSchema = z.object({ generationId: z.string(), model: z.string(), draftedAt: isoDateTime, draftedById: z.string().nullable(), suggestions: z.array(lotseSuggestionSchema), /** plain-language hints of what the model could not find in the data */ missingInformation: z.array(z.string().max(500)).max(LOTSE_MISSING_MAX), reviewedAt: isoDateTime.nullable(), reviewedById: z.string().nullable(), }); export type LotseBlock = z.infer; export const LOTSE_ADDRESS_FORMS = ["sie", "du"] as const; export type LotseAddressForm = (typeof LOTSE_ADDRESS_FORMS)[number]; export function pendingSuggestions(block: LotseBlock | null | undefined): LotseSuggestion[] { return block ? block.suggestions.filter((s) => s.state === "pending") : []; }