@cosyte/synth 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +414 -0
  2. package/LICENSE +21 -0
  3. package/README.md +325 -0
  4. package/dist/astm/index.cjs +847 -0
  5. package/dist/astm/index.cjs.map +1 -0
  6. package/dist/astm/index.d.cts +418 -0
  7. package/dist/astm/index.d.ts +418 -0
  8. package/dist/astm/index.mjs +828 -0
  9. package/dist/astm/index.mjs.map +1 -0
  10. package/dist/ccda/index.cjs +1103 -0
  11. package/dist/ccda/index.cjs.map +1 -0
  12. package/dist/ccda/index.d.cts +380 -0
  13. package/dist/ccda/index.d.ts +380 -0
  14. package/dist/ccda/index.mjs +1077 -0
  15. package/dist/ccda/index.mjs.map +1 -0
  16. package/dist/deid/index.cjs +2809 -0
  17. package/dist/deid/index.cjs.map +1 -0
  18. package/dist/deid/index.d.cts +464 -0
  19. package/dist/deid/index.d.ts +464 -0
  20. package/dist/deid/index.mjs +2793 -0
  21. package/dist/deid/index.mjs.map +1 -0
  22. package/dist/example-codes-DeXcnCSK.d.cts +105 -0
  23. package/dist/example-codes-DeXcnCSK.d.ts +105 -0
  24. package/dist/fhir/index.cjs +1429 -0
  25. package/dist/fhir/index.cjs.map +1 -0
  26. package/dist/fhir/index.d.cts +772 -0
  27. package/dist/fhir/index.d.ts +772 -0
  28. package/dist/fhir/index.mjs +1384 -0
  29. package/dist/fhir/index.mjs.map +1 -0
  30. package/dist/hl7/index.cjs +1012 -0
  31. package/dist/hl7/index.cjs.map +1 -0
  32. package/dist/hl7/index.d.cts +548 -0
  33. package/dist/hl7/index.d.ts +548 -0
  34. package/dist/hl7/index.mjs +990 -0
  35. package/dist/hl7/index.mjs.map +1 -0
  36. package/dist/index.cjs +535 -0
  37. package/dist/index.cjs.map +1 -0
  38. package/dist/index.d.cts +407 -0
  39. package/dist/index.d.ts +407 -0
  40. package/dist/index.mjs +488 -0
  41. package/dist/index.mjs.map +1 -0
  42. package/dist/ncpdp/index.cjs +714 -0
  43. package/dist/ncpdp/index.cjs.map +1 -0
  44. package/dist/ncpdp/index.d.cts +432 -0
  45. package/dist/ncpdp/index.d.ts +432 -0
  46. package/dist/ncpdp/index.mjs +695 -0
  47. package/dist/ncpdp/index.mjs.map +1 -0
  48. package/dist/providers-OLz3zAc-.d.cts +343 -0
  49. package/dist/providers-OLz3zAc-.d.ts +343 -0
  50. package/dist/quirk-DmkgoZdh.d.cts +239 -0
  51. package/dist/quirk-JLyO1Ncj.d.ts +239 -0
  52. package/dist/x12/index.cjs +920 -0
  53. package/dist/x12/index.cjs.map +1 -0
  54. package/dist/x12/index.d.cts +484 -0
  55. package/dist/x12/index.d.ts +484 -0
  56. package/dist/x12/index.mjs +892 -0
  57. package/dist/x12/index.mjs.map +1 -0
  58. package/package.json +210 -0
@@ -0,0 +1,418 @@
1
+ import { S as SyntheticName, R as Rng, C as Corpus } from '../providers-OLz3zAc-.cjs';
2
+ import { Q as QuirkDescriptor, S as SynthProfile, a as QuirkArtifact, b as QuirkRoundTripResult } from '../quirk-DmkgoZdh.cjs';
3
+
4
+ /**
5
+ * Spec-clean ASTM (E1394 / CLSI LIS02) message generation — the `H`/`P`/`O`/`R`/`C`/`L` record report —
6
+ * built through `@cosyte/astm`'s `buildAstmMessage` so the delimiter declaration (`H|\^&`), the record
7
+ * type letters, the per-type sequence counters, the `L` terminator, and every escape are the parser's
8
+ * own conservative emit. Nothing clinical is defaulted: a
9
+ * result's status/flag/units/value are supplied from the example pool, never invented by the builder.
10
+ *
11
+ * A framed **E1381 / CLSI LIS01** variant is also offered ({@link generateAstmResultFramed}) via
12
+ * `composeAstmFrames`, which frames each record into `<STX> FN text <ETB|ETX> CS <CR><LF>` with the
13
+ * **modulo-256 checksum and the `0`–`7` frame number computed by the parser** — never faked. Both round
14
+ * trip through `@cosyte/astm` cleanly (`parseAstmRecords` / `parseFramedAstm` — see `./round-trip`).
15
+ *
16
+ * Every value at a PHI-bearing locus (the `P` record's name / DOB / practice+lab IDs) is
17
+ * drawn from the synthetic-safety providers via `./identity`, so no output can be real or plausibly-real
18
+ * PHI. `synth` is a **format/conformance generator, not a clinical simulator**: a generated
19
+ * result pairs a code and a value with no claim of clinical coherence.
20
+ *
21
+ * @module
22
+ */
23
+ /** Options for the ASTM message generators. */
24
+ interface GenerateAstmOptions {
25
+ /** The seed (deterministic — same seed yields a byte-identical message). */
26
+ readonly seed: number;
27
+ /** How many `R` (result) records to emit. Defaults to a seeded 1–4. */
28
+ readonly resultCount?: number;
29
+ /** Whether to append a `C` (comment) record after the results. Defaults to `true`. */
30
+ readonly comment?: boolean;
31
+ }
32
+ /**
33
+ * Generate a spec-clean ASTM **result message** — an `H`/`P`/`O`/`R`…/`C`/`L` record stream — built
34
+ * through `@cosyte/astm`'s `buildAstmMessage`. Every identity value is synthetic-by-construction; the message
35
+ * round-trips through `parseAstmRecords` with zero warnings and re-serializes
36
+ * byte-identically (see `./round-trip`).
37
+ *
38
+ * @param options - The seed, optional result count, and whether to append a comment.
39
+ * @returns The `CR`-terminated ASTM record stream.
40
+ * @example
41
+ * ```ts
42
+ * import { generateAstmResult } from "@cosyte/synth/astm";
43
+ * const raw = generateAstmResult({ seed: 42 });
44
+ * ```
45
+ */
46
+ declare function generateAstmResult(options: GenerateAstmOptions): string;
47
+ /**
48
+ * Generate a spec-clean ASTM **order message** — an `H`/`P`/`O`/`L` record stream with no results, for
49
+ * the order side of the flow. Built through `buildAstmMessage`; synthetic-by-construction; round-trips
50
+ * clean.
51
+ *
52
+ * @param options - The seed.
53
+ * @returns The `CR`-terminated ASTM record stream.
54
+ * @example
55
+ * ```ts
56
+ * import { generateAstmOrder } from "@cosyte/synth/astm";
57
+ * const raw = generateAstmOrder({ seed: 7 });
58
+ * ```
59
+ */
60
+ declare function generateAstmOrder(options: GenerateAstmOptions): string;
61
+ /**
62
+ * Generate a spec-clean **framed** ASTM result message — the same `H`/`P`/`O`/`R`…/`C`/`L` records,
63
+ * wrapped in the **E1381 / CLSI LIS01** frame envelope (`<STX> FN text <ETB|ETX> CS <CR><LF>`) via
64
+ * `@cosyte/astm`'s `composeAstmFrames`. The **modulo-256 checksum and the `0`–`7` frame number are
65
+ * computed by the parser** (never hand-written), and a record over 240 bytes is split across frames —
66
+ * so the bytes round-trip through `parseFramedAstm` with zero frame **and** record warnings (see
67
+ * `./round-trip`). Each record is framed independently (one `ETX`-closed run per record), mirroring what
68
+ * `decodeAstmFrames` reassembles.
69
+ *
70
+ * @param options - The seed, optional result count, and whether to append a comment.
71
+ * @returns The framed byte stream.
72
+ * @example
73
+ * ```ts
74
+ * import { generateAstmResultFramed } from "@cosyte/synth/astm";
75
+ * const bytes = generateAstmResultFramed({ seed: 42 }); // Uint8Array — E1381 framed
76
+ * ```
77
+ */
78
+ declare function generateAstmResultFramed(options: GenerateAstmOptions): Uint8Array;
79
+
80
+ /**
81
+ * The **round-trip-through-the-parser harness** for ASTM — the headline gate for the synthetic-fixture
82
+ * generator. A generated ASTM record stream (or framed byte stream) is "spec-clean" only
83
+ * if `@cosyte/astm` — not `@cosyte/synth`'s own opinion — reads it back cleanly. Each harness parses the
84
+ * generated wire straight back through the parser and reports what it found, so a false "spec-clean"
85
+ * claim cannot hide.
86
+ *
87
+ * The **record** layer (E1394) and the **frame** layer (E1381) are separate concerns, so each gets its
88
+ * own harness; both report the same {@link AstmRoundTripResult} shape (the framed one additionally folds
89
+ * the frame-layer warnings — bad checksum, sequence gap, unterminated, oversize — into `warnings`, so a
90
+ * framing defect is caught by the same gate).
91
+ *
92
+ * @module
93
+ */
94
+ /** The verdict of one round-trip through `@cosyte/astm`. */
95
+ interface AstmRoundTripResult {
96
+ /** The serialized ASTM wire text (records: the `CR`-terminated stream; framed: the raw bytes as latin1). */
97
+ readonly content: string;
98
+ /** The warning codes the parser emitted on re-parse (record + frame layers). Empty ⇒ spec-clean. */
99
+ readonly warnings: readonly string[];
100
+ /** Whether re-serializing the re-parsed message is byte-identical to the input. */
101
+ readonly byteStable: boolean;
102
+ /** `true` iff the artifact is spec-clean: zero warnings **and** byte-stable. */
103
+ readonly specClean: boolean;
104
+ }
105
+ /**
106
+ * Round-trip a generated ASTM **record** stream through parse → serialize and report the verdict. A
107
+ * spec-clean message re-parses with **zero warnings** and re-serializes byte-identically.
108
+ *
109
+ * @param raw - The ASTM record stream (typically from `generateAstmResult` / `generateAstmOrder`).
110
+ * @returns The {@link AstmRoundTripResult}.
111
+ * @example
112
+ * ```ts
113
+ * import { generateAstmResult, astmRoundTrip } from "@cosyte/synth/astm";
114
+ * const { specClean } = astmRoundTrip(generateAstmResult({ seed: 1 })); // specClean === true
115
+ * ```
116
+ */
117
+ declare function astmRoundTrip(raw: string): AstmRoundTripResult;
118
+ /**
119
+ * Round-trip a generated **framed** ASTM byte stream (E1381) through decode+parse → re-frame and report
120
+ * the verdict. A spec-clean framed message re-parses with **zero record and zero frame warnings** (every
121
+ * modulo-256 checksum verifies, no sequence gap, no unterminated/oversize frame) and re-frames
122
+ * byte-identically.
123
+ *
124
+ * @param bytes - The framed byte stream (typically from `generateAstmResultFramed`).
125
+ * @returns The {@link AstmRoundTripResult} — `content` holds the framed bytes decoded as latin1.
126
+ * @example
127
+ * ```ts
128
+ * import { generateAstmResultFramed, astmFramedRoundTrip } from "@cosyte/synth/astm";
129
+ * const { specClean } = astmFramedRoundTrip(generateAstmResultFramed({ seed: 1 })); // true
130
+ * ```
131
+ */
132
+ declare function astmFramedRoundTrip(bytes: Uint8Array): AstmRoundTripResult;
133
+
134
+ /**
135
+ * Synthetic identity for ASTM (E1394 / CLSI LIS02) messages — every value `synth` puts into a `P`
136
+ * (patient) record, an `O` (order) accession, or the `H` header is minted here, and **only** from the
137
+ * synthetic-safety providers. ASTM's PHI-dense locus is the **`P` record**: it carries the
138
+ * patient **name** (`Last^First^Middle`), **birthdate**, **sex**, and the **practice-assigned** and
139
+ * **laboratory-assigned** patient IDs, which must stay
140
+ * **distinct** (the parser keeps them distinct; a generator that let one default from the other would
141
+ * defeat that). Every identifier is scoped to the synthetic assigning authority: there is no reserved
142
+ * patient-ID range for ASTM (as for MRNs generally), so the **namespace** is the
143
+ * guarantee. The IDs carry a clearly-synthetic prefix (`PRA` / `LAB` / `ACC`) so the `phi-scan` ASTM
144
+ * arm can recognize them as synthetic-AA-scoped and a real bare numeric MRN can never masquerade as one.
145
+ *
146
+ * @module
147
+ */
148
+
149
+ /** A synthetic ASTM patient — every field drawn from `../safe`. */
150
+ interface AstmPatient {
151
+ /** Name from the shipped fake-name pool, plus a fictional middle initial. */
152
+ readonly person: SyntheticName;
153
+ /** Middle initial (clearly synthetic). */
154
+ readonly middle: string;
155
+ /** Birthdate `YYYYMMDD`, from the seeded generator (no real event implied). */
156
+ readonly birthDate: string;
157
+ /** Sex code, emitted verbatim (`M` / `F` — structural, never defaulted by the builder). */
158
+ readonly sex: "M" | "F";
159
+ /** Practice-assigned patient ID — synthetic-AA scoped (`PRA`-prefixed). Distinct from the lab ID. */
160
+ readonly practiceAssignedId: string;
161
+ /** Laboratory-assigned patient ID — synthetic-AA scoped (`LAB`-prefixed). Distinct from the practice ID. */
162
+ readonly laboratoryAssignedId: string;
163
+ }
164
+ /** A synthetic ASTM order identity — the specimen / accession id and priority. */
165
+ interface AstmOrder {
166
+ /** Specimen / accession id — synthetic-AA scoped (`ACC`-prefixed). */
167
+ readonly specimenId: string;
168
+ /** Priority code, emitted verbatim (`R` routine, `S` stat). */
169
+ readonly priority: "R" | "S";
170
+ }
171
+ /** A synthetic ASTM header identity — the sender and analyzer strings for the `H` record. */
172
+ interface AstmHeaderIdentity {
173
+ /** The sending system id (clearly synthetic). */
174
+ readonly sender: string;
175
+ /** The analyzer / instrument string (clearly synthetic). */
176
+ readonly analyzer: string;
177
+ }
178
+ /**
179
+ * Mint a synthetic patient for a `P` record. Fixed draw order (name → middle → DOB → sex → practice id
180
+ * → lab id) so the same seed yields the same patient. The two patient IDs are minted from
181
+ * **independent** synthetic-identifier draws, so they are distinct by construction.
182
+ *
183
+ * @param rng - The seeded generator.
184
+ * @returns A synthetic {@link AstmPatient}.
185
+ * @example
186
+ * ```ts
187
+ * import { createRng } from "@cosyte/synth";
188
+ * import { astmPatient } from "@cosyte/synth/astm";
189
+ * const { person, practiceAssignedId, laboratoryAssignedId } = astmPatient(createRng(1));
190
+ * ```
191
+ */
192
+ declare function astmPatient(rng: Rng): AstmPatient;
193
+ /**
194
+ * Mint a synthetic order identity for an `O` record — a synthetic-AA-scoped accession id and a priority.
195
+ *
196
+ * @param rng - The seeded generator.
197
+ * @returns A synthetic {@link AstmOrder}.
198
+ * @example
199
+ * ```ts
200
+ * import { createRng } from "@cosyte/synth";
201
+ * import { astmOrder } from "@cosyte/synth/astm";
202
+ * const { specimenId } = astmOrder(createRng(1));
203
+ * ```
204
+ */
205
+ declare function astmOrder(rng: Rng): AstmOrder;
206
+ /**
207
+ * Mint a synthetic header identity for the `H` record — a clearly-synthetic sender and analyzer.
208
+ *
209
+ * @param rng - The seeded generator.
210
+ * @returns A synthetic {@link AstmHeaderIdentity}.
211
+ * @example
212
+ * ```ts
213
+ * import { createRng } from "@cosyte/synth";
214
+ * import { astmHeaderIdentity } from "@cosyte/synth/astm";
215
+ * const { sender } = astmHeaderIdentity(createRng(1));
216
+ * ```
217
+ */
218
+ declare function astmHeaderIdentity(rng: Rng): AstmHeaderIdentity;
219
+
220
+ /**
221
+ * A small, **license-clean** pool of example ASTM laboratory tests — the analyte codes, units, and
222
+ * plausible value ranges `synth` draws on when populating `O` (order) and `R` (result) records. The
223
+ * codes are **facts** (a LOINC number is a public identifier, and the local analyzer codes here are
224
+ * invented), never a bundled terminology table. Nothing clinical is asserted — a `synth` result pairs a value
225
+ * and a code with no claim of clinical coherence: the pool exists only to make a *structurally* realistic
226
+ * result record.
227
+ *
228
+ * @module
229
+ */
230
+ /** One example laboratory analyte — its codes, units, reference range, and a seeded value window. */
231
+ interface AstmExampleTest {
232
+ /** A local analyzer test code (invented — never a real vendor assay id). */
233
+ readonly localCode: string;
234
+ /** The public LOINC identifier for the analyte (a fact, not bundled terminology prose). */
235
+ readonly loinc: string;
236
+ /** The human-readable test name, emitted in the Universal Test ID name component. */
237
+ readonly name: string;
238
+ /** The units string, emitted verbatim in `R`-field 5 (never converted or guessed). */
239
+ readonly units: string;
240
+ /** The reference range text, emitted verbatim in `R`-field 6. */
241
+ readonly referenceRange: string;
242
+ /** Inclusive integer low bound of the seeded synthetic value (structural, not clinical). */
243
+ readonly valueLow: number;
244
+ /** Inclusive integer high bound of the seeded synthetic value. */
245
+ readonly valueHigh: number;
246
+ /** Number of decimal places to render the synthetic value with. */
247
+ readonly decimals: number;
248
+ }
249
+ /**
250
+ * The example test pool. A handful of common chemistry/hematology analytes, each with a public LOINC
251
+ * code, invented local code, units, and a value window the seeded generator samples. Frozen — the pool
252
+ * is shared, immutable data.
253
+ *
254
+ * @example
255
+ * ```ts
256
+ * import { EXAMPLE_ASTM_TESTS } from "@cosyte/synth/astm";
257
+ * EXAMPLE_ASTM_TESTS[0]?.name; // "Glucose"
258
+ * ```
259
+ */
260
+ declare const EXAMPLE_ASTM_TESTS: readonly AstmExampleTest[];
261
+ /** HL7 Table 0078 abnormal-flag codes `synth` draws from (emitted verbatim; never defaulted). */
262
+ declare const ASTM_ABNORMAL_FLAGS: readonly string[];
263
+ /** Result-status codes `synth` draws from (`F` final, `P` preliminary, `C` correction). */
264
+ declare const ASTM_RESULT_STATUSES: readonly string[];
265
+ /** Free-text result comments — clearly synthetic, carry no PHI. */
266
+ declare const ASTM_COMMENT_TEXT: readonly string[];
267
+
268
+ /**
269
+ * ASTM E1394 **vendor-quirk generation**. A quirk deviates the
270
+ * *structure* of an otherwise spec-clean record report (built through `@cosyte/astm`'s
271
+ * `buildAstmMessage`) so it round-trips through `parseAstmRecords` to **exactly** one intended, stable
272
+ * warning code — a code in the parser's `defineAstmProfile` tolerable set. Where a built-in public
273
+ * profile tolerates the quirk, the warning is **re-badged** to the value-free `PROFILE_QUIRK_APPLIED`
274
+ * marker (`expected: true`), exactly as the parser's `profileQuirkApplied` does.
275
+ *
276
+ * The deviation is applied **post-serialize** on the record stream. Two quirks ship:
277
+ *
278
+ * - **`unknown-escape`** → `ASTM_UNKNOWN_ESCAPE_SEQUENCE` (profile `referenceCorpus`). A non-standard
279
+ * `&Z&` escape body is injected into a result's units field. Grounded on `@cosyte/astm`'s public
280
+ * `referenceCorpus` profile (the redistributable kxepal/python-astm + senaite OSS corpus), which
281
+ * re-badges it.
282
+ * - **`unknown-record-type`** → `ASTM_RECORD_UNKNOWN_TYPE`. A record's leading type letter is changed to
283
+ * a site-defined `Z` — a real ASTM tolerance (the parser's tolerable set includes this code), but no
284
+ * built-in profile tolerates it, so it is a `"bare"` quirk (a consumer authors a `defineAstmProfile`
285
+ * to re-badge it).
286
+ *
287
+ * A quirk **never** introduces a real-looking value — it changes an escape body or a record type letter,
288
+ * never a P-record identity locus, so the synthetic-safety gate still runs and stays zero.
289
+ *
290
+ * @module
291
+ */
292
+
293
+ /** Every ASTM quirk this package ships. */
294
+ type AstmQuirkName = "unknown-escape" | "unknown-record-type";
295
+ /**
296
+ * Both shipped ASTM quirks are **result-report** deviations — `unknown-escape` targets an `R` record's
297
+ * units field and `unknown-record-type` a `C` (comment) record, neither of which an *order* report
298
+ * carries. So the quirk base is always a result report (`generateAstmResult`).
299
+ */
300
+ type AstmQuirkKind = "Result";
301
+ /** The ASTM quirk registry — each recipe bound to the exact `@cosyte/astm` warning code it targets. */
302
+ declare const ASTM_QUIRKS: Readonly<Record<AstmQuirkName, QuirkDescriptor>>;
303
+ /** Options for {@link generateAstmQuirk}. */
304
+ interface GenerateAstmQuirkOptions {
305
+ /** The seed — the same seed + quirk yields a byte-identical record stream. Defaults to `0`. */
306
+ readonly seed?: number;
307
+ /** The quirk to inject. Required. */
308
+ readonly quirk: AstmQuirkName;
309
+ /** The spec-clean base report kind. Always `"Result"` (see {@link AstmQuirkKind}). */
310
+ readonly kind?: AstmQuirkKind;
311
+ }
312
+ /**
313
+ * Generate one ASTM **quirk** artifact: a spec-clean record report (built through `@cosyte/astm`) with
314
+ * the requested vendor deviation injected post-serialize. Deterministic in `seed` + `quirk` + `kind`.
315
+ *
316
+ * @param options - Seed, quirk, and base kind. See {@link GenerateAstmQuirkOptions}.
317
+ * @returns The {@link QuirkArtifact} — its `content` round-trips to `intendedWarnings` exactly.
318
+ * @throws SynthError `SYNTH_UNSUPPORTED_QUIRK` if `quirk` is not a supported ASTM quirk.
319
+ * @throws Error if the base report does not contain the structural anchor the quirk targets.
320
+ * @example
321
+ * ```ts
322
+ * import { generateAstmQuirk, astmQuirkRoundTrip } from "@cosyte/synth/astm";
323
+ * const rt = astmQuirkRoundTrip(generateAstmQuirk({ seed: 1, quirk: "unknown-escape" }));
324
+ * rt.withProfile?.tolerated; // true — `referenceCorpus` re-badges ASTM_UNKNOWN_ESCAPE_SEQUENCE
325
+ * ```
326
+ */
327
+ declare function generateAstmQuirk(options: GenerateAstmQuirkOptions): QuirkArtifact;
328
+ /**
329
+ * Round-trip an ASTM quirk artifact through `@cosyte/astm` and report the intended-warning verdict: a bare
330
+ * parse must produce **exactly** the intended code, and — when a built-in public
331
+ * profile tolerates the quirk — the profiled parse must re-badge it to `PROFILE_QUIRK_APPLIED`.
332
+ *
333
+ * @param artifact - The quirk artifact (from {@link generateAstmQuirk}).
334
+ * @returns The {@link QuirkRoundTripResult}.
335
+ * @example
336
+ * ```ts
337
+ * import { generateAstmQuirk, astmQuirkRoundTrip } from "@cosyte/synth/astm";
338
+ * astmQuirkRoundTrip(generateAstmQuirk({ seed: 1, quirk: "unknown-escape" })).intendedWarningHeld;
339
+ * ```
340
+ */
341
+ declare function astmQuirkRoundTrip(artifact: QuirkArtifact): QuirkRoundTripResult;
342
+ /** Options for {@link astmQuirkCorpus}. */
343
+ interface AstmQuirkCorpusOptions {
344
+ /** The seed for the whole corpus (deterministic). */
345
+ readonly seed: number;
346
+ /** How many quirk artifacts to generate. Defaults to the number of quirks. */
347
+ readonly count?: number;
348
+ /** The quirk names to cycle through. Defaults to every ASTM quirk. Validated; unsupported ⇒ fatal. */
349
+ readonly quirks?: readonly AstmQuirkName[];
350
+ /** A {@link SynthProfile} whose `quirks` drive the corpus (validated). Takes precedence over `quirks`. */
351
+ readonly profile?: SynthProfile;
352
+ }
353
+ /**
354
+ * Build a reproducible {@link Corpus} of ASTM quirk artifacts. Each artifact's `warnings` record the
355
+ * intended code for its quirk; the manifest lists the applied quirk names.
356
+ *
357
+ * @param options - Seed, count, and the quirk selection. See {@link AstmQuirkCorpusOptions}.
358
+ * @returns A deep-frozen {@link Corpus}.
359
+ * @example
360
+ * ```ts
361
+ * import { astmQuirkCorpus } from "@cosyte/synth/astm";
362
+ * astmQuirkCorpus({ seed: 42 }).manifest.quirks; // the applied quirk names
363
+ * ```
364
+ */
365
+ declare function astmQuirkCorpus(options: AstmQuirkCorpusOptions): Corpus;
366
+ /** A ready-made {@link SynthProfile} requesting every built-in ASTM quirk. */
367
+ declare const astmQuirkProfile: SynthProfile;
368
+
369
+ /**
370
+ * `@cosyte/synth/astm` — the ASTM generation surface, exposed as its own subpath so importing the
371
+ * package root does **not** pull `@cosyte/astm`. This is the **lazy, per-format** boundary: a consumer
372
+ * who only needs ASTM fixtures imports `@cosyte/synth/astm`; one who needs only the core primitives
373
+ * never loads a parser.
374
+ * `@cosyte/astm` is an **optional peer dependency** — present only for this subpath.
375
+ *
376
+ * This subpath ships spec-clean generation of the E1394 record report and its E1381 framed twin, each
377
+ * built through `@cosyte/astm`'s own emit surface:
378
+ *
379
+ * - **Records (E1394):** `generateAstmResult` (`H`/`P`/`O`/`R`…/`C`/`L`) and `generateAstmOrder`
380
+ * (`H`/`P`/`O`/`L`) via `buildAstmMessage` — each round-tripping through `parseAstmRecords` with zero
381
+ * warnings and byte-stable, and carrying a `P` record whose name / DOB / practice+lab IDs are all
382
+ * synthetic-by-construction. The practice- and laboratory-assigned patient IDs are
383
+ * minted independently, so they stay **distinct**.
384
+ * - **Framing (E1381):** `generateAstmResultFramed` via `composeAstmFrames` — the modulo-256 checksum
385
+ * and the `0`–`7` frame number are **computed by the parser, never faked**, and the bytes round-trip
386
+ * through `parseFramedAstm` with zero frame **and** record warnings.
387
+ *
388
+ * @module
389
+ */
390
+
391
+ /** Every ASTM message kind {@link astmCorpus} generates — the label used as the corpus `kind`. */
392
+ type AstmCorpusKind = "Result" | "Order";
393
+ /** Options for {@link astmCorpus}. */
394
+ interface AstmCorpusOptions {
395
+ /** The seed for the whole corpus (deterministic). */
396
+ readonly seed: number;
397
+ /** How many messages to generate. Defaults to the length of the mix. */
398
+ readonly count?: number;
399
+ /** The message kinds to cycle through. Defaults to one of each. */
400
+ readonly mix?: readonly AstmCorpusKind[];
401
+ }
402
+ /**
403
+ * Build a reproducible {@link Corpus} of spec-clean ASTM messages. Each message is generated from a
404
+ * distinct sub-seed derived from the corpus seed (so the set is deterministic) and round-tripped through
405
+ * `@cosyte/astm`; the per-artifact `warnings` record the parser's verdict (empty ⇒ spec-clean).
406
+ *
407
+ * @param options - Seed, count, and the message mix. See {@link AstmCorpusOptions}.
408
+ * @returns A deep-frozen {@link Corpus}.
409
+ * @example
410
+ * ```ts
411
+ * import { astmCorpus } from "@cosyte/synth/astm";
412
+ * const corpus = astmCorpus({ seed: 42 });
413
+ * corpus.artifacts.every((a) => a.warnings.length === 0); // true — spec-clean
414
+ * ```
415
+ */
416
+ declare function astmCorpus(options: AstmCorpusOptions): Corpus;
417
+
418
+ export { ASTM_ABNORMAL_FLAGS, ASTM_COMMENT_TEXT, ASTM_QUIRKS, ASTM_RESULT_STATUSES, type AstmCorpusKind, type AstmCorpusOptions, type AstmExampleTest, type AstmHeaderIdentity, type AstmOrder, type AstmPatient, type AstmQuirkCorpusOptions, type AstmQuirkKind, type AstmQuirkName, type AstmRoundTripResult, EXAMPLE_ASTM_TESTS, type GenerateAstmOptions, type GenerateAstmQuirkOptions, astmCorpus, astmFramedRoundTrip, astmHeaderIdentity, astmOrder, astmPatient, astmQuirkCorpus, astmQuirkProfile, astmQuirkRoundTrip, astmRoundTrip, generateAstmOrder, generateAstmQuirk, generateAstmResult, generateAstmResultFramed };