Files
0pt/lib/import-dispatch-policy.ts
T

48 lines
2.1 KiB
TypeScript

// DES1GN ADR D3 (§31): bulk-import dispatch-policy — ETT objekt, en sanning.
//
// Import-routen (/api/orders/import) är inline-exekvering med hårt tak. Rader
// över maxRows är DES1GN D3:s signal för N0D-dispatch (job_type
// 0pt.import_execute_job / capability 0pt.import_execute i n0d:s
// JOB_TYPE_REGISTRY). TILLS descriptor-gaten släpper (N0D-worker
// UNVERIFIED) svarar routen 413 med n0d_dispatch_required + hint — aldrig
// tyst trunkering, aldrig tyst dispatch.
export const IMPORT_DISPATCH_POLICY = {
/** Inline-tak i import-routen (oförändrat beteendekontrakt, 0pt#53). */
maxInlineRows: 500,
/** N0D-dispatch-signal: rader över detta är ett N0D-jobb, inget HTTP-anrop. */
maxRows: 5000,
/** Byte-tak för hela CSV-kroppen (UTF-8). */
maxBytes: 1_000_000,
/** Format-allowlist — endast RFC 4180 CSV i dag. */
allowedFormats: ["csv"] as readonly string[],
} as const;
export type ImportDispatchPolicy = typeof IMPORT_DISPATCH_POLICY;
export type ImportDispatchVerdict =
| { verdict: "inline" }
| { verdict: "unsupported_format"; format: string }
| { verdict: "byte_cap_exceeded"; bytes: number; maxBytes: number }
| { verdict: "row_cap_exceeded"; rows: number; maxInlineRows: number }
| { verdict: "dispatch_n0d"; rows: number; maxRows: number };
/** Ren funktion — inga I/O, fullt deterministisk, testad per kombination. */
export function evaluateImportDispatch(
input: { format: string; bytes: number; rows: number },
policy: ImportDispatchPolicy = IMPORT_DISPATCH_POLICY,
): ImportDispatchVerdict {
if (!policy.allowedFormats.includes(input.format)) {
return { verdict: "unsupported_format", format: input.format };
}
if (input.bytes > policy.maxBytes) {
return { verdict: "byte_cap_exceeded", bytes: input.bytes, maxBytes: policy.maxBytes };
}
if (input.rows > policy.maxRows) {
return { verdict: "dispatch_n0d", rows: input.rows, maxRows: policy.maxRows };
}
if (input.rows > policy.maxInlineRows) {
return { verdict: "row_cap_exceeded", rows: input.rows, maxInlineRows: policy.maxInlineRows };
}
return { verdict: "inline" };
}