@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
package/README.md ADDED
@@ -0,0 +1,325 @@
1
+ # @cosyte/synth
2
+
3
+ > Deterministic, seedable **synthetic healthcare-fixture generator** for Node.js and TypeScript —
4
+ > spec-clean by construction, and **never real PHI**.
5
+
6
+ `@cosyte/synth` generates reproducible synthetic test corpora across the six cosyte formats (HL7 v2,
7
+ FHIR R4 / US Core, C-CDA, X12, NCPDP, and ASTM). It is a **consumer** of the
8
+ cosyte parsers, not a parser: it builds each artifact **through the parser's own builder/serializer**
9
+ (so the output is spec-clean by the same mechanism the parser proves) and draws every identifier, name,
10
+ date, phone, and address from a **guaranteed-non-colliding synthetic source**. It is a
11
+ **format/conformance generator, not a clinical simulator** — it does not model disease progression
12
+ (that is Synthea).
13
+
14
+ > **Status:** pre-alpha (`0.0.x`), not yet published to npm. The generator is **feature-complete**: the
15
+ > seeded-PRNG core, the synthetic-safety providers, and the round-trip harness; **spec-clean generation
16
+ > across all six formats** — HL7 v2 (`ADT`/`ORU`/`ORM`/`SIU`/`VXU`), FHIR R4 / US Core (the full clinical
17
+ > set + `collection`/`transaction`/`document` Bundles), C-CDA R2.1 (CCD + Referral Note), X12 005010
18
+ > (837P/I/D, 835, 271), NCPDP (SCRIPT NewRx / RxRenewal / RxChange + Telecom B1/B2/B3), and ASTM (E1394
19
+ > record reports + E1381 framing), each built **through its parser's own builder/serializer**; **vendor-quirk
20
+ > mode** — profile-driven off-spec fixtures for the three richest profile systems (**HL7 v2, C-CDA, ASTM**),
21
+ > each round-tripping to exactly the intended parser warning (the intended-warning contract); and the
22
+ > **`@cosyte/deid` pairing loop** — a closed-loop co-validation harness that de-identifies generated output
23
+ > and proves every planted synthetic PHI sentinel is removed.
24
+ >
25
+ > **Deferred (honestly out of scope for now):** quirk recipes for **FHIR / X12 / NCPDP** (and any quirk
26
+ > needing a private vendor corpus); the X12 **270** eligibility _request_ and NCPDP SCRIPT lifecycle
27
+ > **responses** (both track the parsers' builder surfaces); **NCPDP SCRIPT / ASTM / DICOM** de-identify
28
+ > pairing (no `@cosyte/deid` adapter, or not generated); and optional **Synthea** clinical-content ingestion.
29
+ > The two remaining founder gates are the actual `npm publish` and the repo public-flip.
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ npm install @cosyte/synth @cosyte/hl7 @cosyte/fhir @cosyte/ccda @cosyte/x12 @cosyte/ncpdp @cosyte/astm
35
+ ```
36
+
37
+ `@cosyte/hl7`, `@cosyte/fhir`, `@cosyte/ccda`, `@cosyte/x12`, `@cosyte/ncpdp`, `@cosyte/astm`, and
38
+ `@cosyte/deid` are **optional peer dependencies**, each needed only for its subpath (`@cosyte/synth/hl7`,
39
+ `@cosyte/synth/fhir`, `@cosyte/synth/ccda`, `@cosyte/synth/x12`, `@cosyte/synth/ncpdp`,
40
+ `@cosyte/synth/astm`, and `@cosyte/synth/deid` — the last needs `@cosyte/deid` **plus** the parsers for
41
+ the formats it pairs) — install only the packages whose fixtures you generate. The package core has
42
+ **zero third-party runtime dependencies**.
43
+
44
+ ## Generate a spec-clean HL7 v2 message
45
+
46
+ The HL7 v2 set covers `ADT` (`A01`/`A04`/`A08`), `ORU^R01`, `ORM^O01`, `SIU^S12`, and `VXU^V04` —
47
+ each built through `@cosyte/hl7`'s `buildMessage`, so it is spec-clean by construction.
48
+
49
+ ```ts
50
+ import { generateAdt, generateOru, generateHl7, hl7Corpus, roundTrip } from "@cosyte/synth/hl7";
51
+
52
+ // Same seed → byte-identical message, on any machine, any run.
53
+ const adt = generateAdt({ seed: 12345, trigger: "A01" });
54
+ const oru = generateOru({ seed: 12345 });
55
+
56
+ // Spec-clean by construction: it round-trips through @cosyte/hl7 with zero warnings.
57
+ roundTrip(adt).specClean; // true
58
+ roundTrip(oru).specClean; // true
59
+
60
+ // Or generate a reproducible mixed corpus across every family:
61
+ const corpus = hl7Corpus({ seed: 42, count: 7 }); // one of each family, cycled
62
+ corpus.artifacts.every((a) => a.warnings.length === 0); // true — all spec-clean
63
+
64
+ // Dispatch by kind when the message type is data:
65
+ generateHl7("VXU^V04", 12345);
66
+ ```
67
+
68
+ ## Generate a spec-clean FHIR R4 / US Core resource
69
+
70
+ The `@cosyte/synth/fhir` subpath builds resources **through `@cosyte/fhir`'s model constructors**, so
71
+ they are spec-clean by construction — validating under `validateResource` and, against the **real US
72
+ Core 6.1.0 profiles** (bring your own `StructureDefinition`s — none is bundled), conformant to US Core.
73
+ The clinical set covers `Patient` (base + US Core), `Condition`, `Observation` (US Core Laboratory
74
+ Result + Vital Signs), `MedicationRequest`, `Encounter`, `DiagnosticReport`, `Immunization`,
75
+ `AllergyIntolerance`, and `Procedure`, assembled into a `collection`, `transaction`, or `document`
76
+ `Bundle`.
77
+
78
+ ```ts
79
+ import { generatePatient, generateBundle, fhirCorpus, roundTrip } from "@cosyte/synth/fhir";
80
+
81
+ // A US Core Patient — same seed → byte-identical resource, anywhere.
82
+ const patient = generatePatient({ seed: 12345, profile: "us-core" });
83
+
84
+ // Spec-clean by construction: it round-trips through @cosyte/fhir with zero errors, byte-stable.
85
+ roundTrip(patient).specClean; // true
86
+
87
+ // A self-contained Bundle assembling a patient + its clinical spine, wired by urn:uuid references:
88
+ const bundle = generateBundle({ seed: 42, type: "transaction" });
89
+
90
+ // Or a reproducible mixed corpus across the whole spine:
91
+ const corpus = fhirCorpus({ seed: 2026, count: 6 });
92
+ corpus.artifacts.every((a) => a.warnings.length === 0); // true — all spec-clean
93
+ ```
94
+
95
+ `@cosyte/fhir` is an **optional peer dependency**, needed only for the `@cosyte/synth/fhir` subpath.
96
+
97
+ ## Generate a spec-clean C-CDA document
98
+
99
+ The `@cosyte/synth/ccda` subpath builds Consolidated CDA R2.1 documents **through `@cosyte/ccda`'s
100
+ `buildCcda`**, so template IDs, LOINC section codes, and structured/narrative agreement are the
101
+ builder's own — the document round-trips through `parseCcda` with **zero warnings**. It emits a
102
+ **CCD** (`generateCcd`) or a **Referral Note** (`generateReferralNote`), each with the CCD sections
103
+ (Problems, Allergies, Medications, Results, Vital Signs, Immunizations, Procedures, Social History)
104
+ populated from the reused, license-clean example-code pools.
105
+
106
+ ```ts
107
+ import { serializeCcda } from "@cosyte/ccda";
108
+ import { generateCcd, generateReferralNote, ccdaCorpus, roundTrip } from "@cosyte/synth/ccda";
109
+
110
+ // Same seed → byte-identical document. The patient name is from the shipped fake-name pool, the MRN
111
+ // lives under a synthetic assigning-authority OID, and every date comes from the seeded generator.
112
+ const ccd = generateCcd({ seed: 12345 });
113
+ serializeCcda(ccd); // spec-clean C-CDA R2.1 XML
114
+
115
+ // Spec-clean by construction: it round-trips through @cosyte/ccda with zero warnings.
116
+ roundTrip(ccd).specClean; // true
117
+ roundTrip(generateReferralNote({ seed: 12345 })).specClean; // true
118
+
119
+ // Or a reproducible mixed corpus (CCD + Referral Note, cycled):
120
+ const corpus = ccdaCorpus({ seed: 42, count: 4 });
121
+ corpus.artifacts.every((a) => a.warnings.length === 0); // true — all spec-clean
122
+ ```
123
+
124
+ `@cosyte/ccda` is an **optional peer dependency**, needed only for the `@cosyte/synth/ccda` subpath.
125
+
126
+ ## Generate a spec-clean X12 transaction
127
+
128
+ The `@cosyte/synth/x12` subpath builds HIPAA **005010** transactions **through `@cosyte/x12`'s domain
129
+ builders** (`build837P/I/D`, `build835`, `build271`), so the ISA/GS/ST…SE/GE/IEA envelope, the
130
+ computed HL spine, the control numbers, and every segment are the builder's own — each transaction
131
+ round-trips through `@cosyte/x12` with **zero warnings**. It emits **837** professional / institutional
132
+ / dental claims, the **835** remittance (balance-checked by construction), and the **271** eligibility
133
+ response.
134
+
135
+ ```ts
136
+ import { generate837P, generate835, generate271, x12Corpus, roundTrip } from "@cosyte/synth/x12";
137
+
138
+ // Same seed → byte-identical EDI. Every subscriber/patient/provider identifier is
139
+ // synthetic-by-construction: the provider NPI has a deliberately-INVALID Luhn check digit (so it can
140
+ // never be a NPPES-issued NPI), the provider tax id is an SSA never-issued 900-range SSN, member ids
141
+ // live under a synthetic assigning authority, and names come from the shipped fake-name pool.
142
+ const claim = generate837P({ seed: 12345 });
143
+ roundTrip(claim).specClean; // true — re-parses through @cosyte/x12 with zero warnings, byte-stable
144
+ roundTrip(generate835({ seed: 7 })).specClean; // true
145
+ roundTrip(generate271({ seed: 3 })).specClean; // true
146
+
147
+ // Or a reproducible mixed corpus (837P/I/D + 835 + 271):
148
+ const corpus = x12Corpus({ seed: 42 });
149
+ corpus.artifacts.every((a) => a.warnings.length === 0); // true — all spec-clean
150
+ ```
151
+
152
+ `@cosyte/x12` is an **optional peer dependency**, needed only for the `@cosyte/synth/x12` subpath.
153
+
154
+ **Deferred:** the **270** eligibility _request_ (`@cosyte/x12` ships a `build271` but no `build270`, and
155
+ `synth` never hand-writes bytes around a missing builder) and **vendor-quirk mode**.
156
+
157
+ ## Generate a spec-clean NCPDP message
158
+
159
+ The `@cosyte/synth/ncpdp` subpath builds both NCPDP standards **through `@cosyte/ncpdp`'s own emit
160
+ surface**, so each message round-trips through the parser with **zero warnings**. It emits **SCRIPT**
161
+ ePrescribing (`generateNewRx` via `buildNewRx`; `generateRxRenewalRequest` / `generateRxChangeRequest`
162
+ via the parser's typed `ScriptMessage` model + `serializeScript`) and **Telecom** pharmacy claims
163
+ (`generateB1` billing / `generateB2` reversal / `generateB3` rebill via `buildTelecomRequest`).
164
+
165
+ ```ts
166
+ import {
167
+ generateNewRx,
168
+ generateB1,
169
+ ncpdpCorpus,
170
+ scriptRoundTrip,
171
+ telecomRoundTrip,
172
+ } from "@cosyte/synth/ncpdp";
173
+
174
+ // Same seed → byte-identical output. NCPDP carries patient AND prescriber identity: the prescriber NPI
175
+ // has a deliberately-INVALID Luhn check digit and the prescriber DEA a deliberately-INVALID checksum
176
+ // (so neither can denote a real provider); patient/cardholder ids live under a synthetic assigning
177
+ // authority, phones are reserved 555-01xx, and names come from the shipped fake-name pool.
178
+ scriptRoundTrip(generateNewRx({ seed: 12345 })).specClean; // true — zero warnings, byte-stable
179
+ telecomRoundTrip(generateB1({ seed: 777 })).specClean; // true
180
+
181
+ // Or a reproducible mixed corpus (NewRx + RxRenewal + RxChange + B1 + B2 + B3):
182
+ const corpus = ncpdpCorpus({ seed: 42 });
183
+ corpus.artifacts.every((a) => a.warnings.length === 0); // true — all spec-clean
184
+ ```
185
+
186
+ `@cosyte/ncpdp` is an **optional peer dependency**, needed only for the `@cosyte/synth/ncpdp` subpath.
187
+
188
+ **Deferred:** vendor-quirk mode. SCRIPT coverage tracks the parser's builder surface: the
189
+ renewal/change _responses_ land as `@cosyte/ncpdp` grows builders.
190
+
191
+ ## Generate a spec-clean ASTM message
192
+
193
+ The `@cosyte/synth/astm` subpath builds ASTM laboratory messages **through `@cosyte/astm`'s own emit
194
+ surface** — `buildAstmMessage` for the E1394 record layer, `composeAstmFrames` for the E1381 frame
195
+ layer — so each message round-trips through the parser with **zero warnings**. It emits the
196
+ `H`/`P`/`O`/`R`…/`C`/`L` **result report** (`generateAstmResult`), the `H`/`P`/`O`/`L` **order**
197
+ (`generateAstmOrder`), and the **framed** twin (`generateAstmResultFramed`).
198
+
199
+ ```ts
200
+ import {
201
+ generateAstmResult,
202
+ generateAstmResultFramed,
203
+ astmRoundTrip,
204
+ astmFramedRoundTrip,
205
+ astmCorpus,
206
+ } from "@cosyte/synth/astm";
207
+
208
+ // Same seed → byte-identical output. The P (patient) record carries the name, birthdate, and the
209
+ // practice- and laboratory-assigned patient ids — all synthetic-by-construction: names from the shipped
210
+ // fake-name pool, DOB seeded, and the two ids minted independently under a synthetic assigning authority
211
+ // (so they stay DISTINCT, exactly as @cosyte/astm keeps them on parse).
212
+ astmRoundTrip(generateAstmResult({ seed: 12345 })).specClean; // true — zero warnings, byte-stable
213
+
214
+ // The E1381-framed twin: the modulo-256 checksum and 0–7 frame numbers are computed by @cosyte/astm.
215
+ astmFramedRoundTrip(generateAstmResultFramed({ seed: 12345 })).specClean; // true
216
+
217
+ // Or a reproducible mixed corpus (a result report + an order):
218
+ const corpus = astmCorpus({ seed: 42 });
219
+ corpus.artifacts.every((a) => a.warnings.length === 0); // true — all spec-clean
220
+ ```
221
+
222
+ `@cosyte/astm` is an **optional peer dependency**, needed only for the `@cosyte/synth/astm` subpath.
223
+
224
+ ## Generate a vendor-quirk fixture
225
+
226
+ Spec-clean fixtures test that a parser reads a _correct_ message; **quirk mode** tests that it tolerates
227
+ the realistic vendor deviations real traffic carries — and surfaces exactly the right diagnostic. The
228
+ quirk vocabulary **is the parsers' own profile systems**: a quirk deviates the message _structure_ so it
229
+ round-trips to **exactly one intended, stable warning code** (the **intended-warning contract**), and
230
+ where a built-in **public** parser profile claims the deviation, it round-trips cleanly under it
231
+ (suppressed, or re-badged to `PROFILE_QUIRK_APPLIED`). A quirk never introduces a real-looking value —
232
+ it changes shape, never provenance, so the synthetic-safety gate still passes.
233
+
234
+ Quirks ship for the three richest profile systems — **HL7 v2, C-CDA, and ASTM**:
235
+
236
+ ```ts
237
+ import { generateHl7Quirk, hl7QuirkRoundTrip } from "@cosyte/synth/hl7";
238
+ import { generateCcdaQuirk, ccdaQuirkRoundTrip } from "@cosyte/synth/ccda";
239
+ import { generateAstmQuirk, astmQuirkRoundTrip } from "@cosyte/synth/astm";
240
+
241
+ // A site-defined HL7 v2 Z-segment → exactly UNKNOWN_SEGMENT; the `visage` profile suppresses it.
242
+ hl7QuirkRoundTrip(generateHl7Quirk({ seed: 1, quirk: "unknown-zsegment" })).warnings; // ["UNKNOWN_SEGMENT"]
243
+
244
+ // A deprecated C-CDA LOINC → exactly DEPRECATED_LOINC; `smartScorecard` re-badges it.
245
+ ccdaQuirkRoundTrip(generateCcdaQuirk({ seed: 1, quirk: "deprecated-loinc" })).withProfile
246
+ ?.tolerated; // true
247
+
248
+ // A non-standard ASTM &Z& escape → exactly ASTM_UNKNOWN_ESCAPE_SEQUENCE; `referenceCorpus` re-badges it.
249
+ astmQuirkRoundTrip(generateAstmQuirk({ seed: 1, quirk: "unknown-escape" })).intendedWarningHeld; // true
250
+ ```
251
+
252
+ A quirk a format's profile system does not support fails closed with a stable `SYNTH_UNSUPPORTED_QUIRK`
253
+ diagnostic — never a silently-wrong fixture. Every quirk is grounded in a **publicly-documented**
254
+ deviation or a parser's **public** profile, never a private vendor corpus.
255
+
256
+ **Deferred:** quirk recipes for **FHIR, X12, and NCPDP**, and any quirk that would need a **private,
257
+ vendor-attributed corpus** to ground.
258
+
259
+ ## Co-validate with `@cosyte/deid` (the pairing loop)
260
+
261
+ The `@cosyte/synth/deid` subpath is a deterministic **closed-loop co-validation harness** for the
262
+ `synth` ⇄ `deid` pair: it **generates** a spec-clean artifact, **plants** distinctive synthetic PHI
263
+ sentinels at the patient loci, **de-identifies** it through `@cosyte/deid`, and **verifies** every
264
+ sentinel is gone from the output (a surviving sentinel is a hard failure) while the clinical payload
265
+ survives (the over-scrub guard).
266
+
267
+ ```ts
268
+ import {
269
+ hl7DeidLoop,
270
+ fhirDeidLoop,
271
+ x12DeidLoop,
272
+ ncpdpTelecomDeidLoop,
273
+ ccdaDeidLoop,
274
+ summarizeDeidCoverage,
275
+ } from "@cosyte/synth/deid";
276
+
277
+ const r = hl7DeidLoop({ seed: 42, kind: "ORU^R01" });
278
+ r.pass; // true
279
+ r.survivors; // [] — every planted synthetic PHI sentinel was removed
280
+ r.clinicalScrubbed; // [] — no clinical value was over-scrubbed
281
+
282
+ const summary = summarizeDeidCoverage([
283
+ hl7DeidLoop({ seed: 1 }),
284
+ fhirDeidLoop({ seed: 1 }),
285
+ x12DeidLoop({ seed: 1, variant: "837P" }),
286
+ ncpdpTelecomDeidLoop({ seed: 1, transaction: "B1" }),
287
+ ccdaDeidLoop({ seed: 1 }),
288
+ ]);
289
+ summary.allPass; // true — zero survivors, zero over-scrub, per format
290
+ ```
291
+
292
+ This is a **co-validation harness, not an independent audit** of `@cosyte/deid` against real-world
293
+ data — it proves the pair works on `synth`'s own output. The removal check is **locus-scoped**: it
294
+ sweeps only the de-identified values remaining at the former PHI loci, so provider/organization
295
+ identity a de-identifier legitimately retains never reads as a false survivor. `@cosyte/deid` is an
296
+ **optional peer dependency**, needed only for this subpath. **Skipped and named** (`DEID_LOOP_SKIPPED`):
297
+ NCPDP **SCRIPT** and **ASTM** (no `@cosyte/deid` adapter) and **DICOM** (not generated by `synth`).
298
+
299
+ ## Draw a synthetic value
300
+
301
+ ```ts
302
+ import { createRng, safe, isSyntheticSsn, isSyntheticNpi } from "@cosyte/synth";
303
+
304
+ const rng = createRng(42);
305
+ isSyntheticSsn(safe.ssn(rng)); // true — always an SSA never-issued SSN
306
+ isSyntheticNpi(safe.npi(rng)); // true — always a deliberately-invalid-Luhn NPI (never a real NPI)
307
+ ```
308
+
309
+ ## What makes it trustworthy
310
+
311
+ - **Synthetic-by-construction** — no code path emits a value not drawn from a reserved range or the
312
+ shipped fake-name pool (SSA never-issued SSNs, NANP `555-01xx` phones, RFC 2606/6761 `example.*`
313
+ domains, RFC 5737/3849 TEST-NET IPs, a synthetic assigning authority for MRNs). A CI gate proves it.
314
+ **No generated value can be real or plausibly-real PHI.**
315
+ - **Spec-clean by the parser's own judgment** — built through the parser's conservative serializer, and
316
+ checked by feeding the artifact straight back in: a spec-clean artifact re-parses with zero warnings.
317
+ - **Deterministic** — a hand-rolled seeded PRNG (`sfc32`/`splitmix32`); `Math.random` is lint-banned.
318
+ A seed, and only the seed, determines the output — byte-for-byte, anywhere.
319
+ - **Immutable** — generated artifacts and the `Corpus` result are deep-frozen.
320
+ - **Zero third-party runtime dependencies** — the parser peers are first-party cosyte packages,
321
+ vendored for dev/test; dual ESM + CJS, validated with `attw`.
322
+
323
+ ## License
324
+
325
+ MIT © Cosyte