import { z } from "zod"; /** Query params accepted by `GET /internal/tech-steps/audit-batch` and `GET /internal/tech-steps/pending-corrections` — both just a bound on how much work one call asks for, so the worker controls its own batch size rather than the server guessing. */ export const workerBatchQuerySchema = z.object({ limit: z.coerce.number().int().positive().max(500).default(50), }); /** Inferred TS type for {@link workerBatchQuerySchema}'s validated output. */ export type WorkerBatchQueryInput = z.infer; /** `locale` param `GET /internal/tech-steps/audit-batch` also accepts, on top of {@link workerBatchQuerySchema} — which of `TECH_STEP_TRAINING_DATA`'s locales to sample steps' clauses against (see `tech-step-matcher.ts`'s `matchTechStepSpans` for the same parameter on the read side). No closed enum here (unlike `recipeVisibilitySchema`) — the training data's own locale list can grow without a schema change. */ export const auditBatchQuerySchema = workerBatchQuerySchema.extend({ locale: z.string().min(2).default("fr"), }); /** Inferred TS type for {@link auditBatchQuerySchema}'s validated output. */ export type AuditBatchQueryInput = z.infer; /** * One suggestion in the batch `POST /internal/tech-steps/training-suggestions` * accepts — `techStepKey` (not an id) since the worker never has direct DB * access to resolve one itself; the API resolves it, and rejects the whole * batch with `TECH_STEP_NOT_FOUND` if any key is unknown (see * `tech-step-worker.service.ts`). `sourceCorrectionId` is required when * `sourceType` is `"correction"` (that's the whole point of that source — * it exists *because of* one specific correction) and must be absent * otherwise — enforced by the refinement below, not by two separate * schemas, so the error message can point at exactly which field is wrong. */ const trainingSuggestionSchema = z .object({ techStepKey: z.string().min(1), locale: z.string().min(2), suggestedSynonyms: z.array(z.string().trim().min(1)), suggestedUtterances: z.array(z.string().trim().min(1)), sourceType: z.enum(["correction", "llm_audit"]), sourceCorrectionId: z.number().int().positive().nullable().optional(), }) .refine( (input) => input.sourceType === "correction" ? input.sourceCorrectionId !== null && input.sourceCorrectionId !== undefined : input.sourceCorrectionId === null || input.sourceCorrectionId === undefined, { message: "sourceCorrectionId is required when sourceType is 'correction', and must be absent otherwise", path: ["sourceCorrectionId"], }, ); /** Payload accepted by `POST /internal/tech-steps/training-suggestions` — a batch, not one suggestion per call, since the worker's audit/correction jobs naturally produce several at once per run and there's no reason to round-trip once per suggestion. */ export const submitTrainingSuggestionsSchema = z.object({ suggestions: z.array(trainingSuggestionSchema).min(1), }); /** Inferred TS type for {@link submitTrainingSuggestionsSchema}'s validated output. */ export type SubmitTrainingSuggestionsInput = z.infer;