diff --git a/README.md b/README.md index 2556196..19c8802 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,12 @@ # @cosyte/synth > Deterministic, seedable **synthetic healthcare-fixture generator** for Node.js and TypeScript: -> spec-clean by construction, and **never real PHI**. +> built through each parser's own builder, and **never real PHI**. `@cosyte/synth` generates reproducible synthetic test corpora across the six Cosyte formats (HL7 v2, FHIR R4 / US Core, C-CDA, X12, NCPDP, and ASTM). It is a **consumer** of the cosyte parsers, not a parser: it builds each artifact **through the parser's own builder/serializer** -(so the output is spec-clean by the same mechanism the parser proves) and draws every identifier, name, +(so each artifact re-parses through that parser with zero warnings) and draws every identifier, name, date, phone, and address from a **guaranteed-non-colliding synthetic source**. It is a **format/conformance generator, not a clinical simulator**: it does not model disease progression (that is Synthea). @@ -21,8 +21,8 @@ date, phone, and address from a **guaranteed-non-colliding synthetic source**. I > **Status:** `0.1`, published to npm. The version shown on the npm package page is the one that is > live; this page never repeats it. Below 1.0, a breaking change raises the minor version and the > changelog says what broke. The generator is **feature-complete**: the -> seeded-PRNG core, the synthetic-safety providers, and the round-trip harness; **spec-clean generation -> across all six formats**, HL7 v2 (`ADT`/`ORU`/`ORM`/`SIU`/`VXU`), FHIR R4 / US Core (the full clinical +> seeded-PRNG core, the synthetic-safety providers, and the round-trip harness; **generation across all +> six formats**, HL7 v2 (`ADT`/`ORU`/`ORM`/`SIU`/`VXU`), FHIR R4 / US Core (the full clinical > set + `collection`/`transaction`/`document` Bundles), C-CDA R2.1 (CCD + Referral Note), X12 005010 > (837P/I/D, 835, 271), NCPDP (SCRIPT NewRx / RxRenewal / RxChange + Telecom B1/B2/B3), and ASTM (E1394 > record reports + E1381 framing), each built **through its parser's own builder/serializer**; **vendor-quirk @@ -136,7 +136,7 @@ corpus.artifacts.every((a) => a.warnings.length === 0); // true, all spec-clean `@cosyte/ccda` is an **optional peer dependency**, needed only for the `@cosyte/synth/ccda` subpath. -## Generate a spec-clean X12 transaction +## Generate an X12 transaction The `@cosyte/synth/x12` subpath builds HIPAA **005010** transactions **through `@cosyte/x12`'s domain builders** (`build837P/I/D`, `build835`, `build271`), so the ISA/GS/ST…SE/GE/IEA envelope, the @@ -159,7 +159,7 @@ roundTrip(generate271({ seed: 3 })).specClean; // true // Or a reproducible mixed corpus (837P/I/D + 835 + 271): const corpus = x12Corpus({ seed: 42 }); -corpus.artifacts.every((a) => a.warnings.length === 0); // true, all spec-clean +corpus.artifacts.every((a) => a.warnings.length === 0); // true ``` `@cosyte/x12` is an **optional peer dependency**, needed only for the `@cosyte/synth/x12` subpath. @@ -167,7 +167,7 @@ corpus.artifacts.every((a) => a.warnings.length === 0); // true, all spec-clean **Deferred:** the **270** eligibility _request_ (`@cosyte/x12` ships a `build271` but no `build270`, and `synth` never hand-writes bytes around a missing builder) and **vendor-quirk mode**. -## Generate a spec-clean NCPDP message +## Generate an NCPDP message The `@cosyte/synth/ncpdp` subpath builds both NCPDP standards **through `@cosyte/ncpdp`'s own emit surface**, so each message round-trips through the parser with **zero warnings**. It emits **SCRIPT** @@ -193,7 +193,7 @@ telecomRoundTrip(generateB1({ seed: 777 })).specClean; // true // Or a reproducible mixed corpus (NewRx + RxRenewal + RxChange + B1 + B2 + B3): const corpus = ncpdpCorpus({ seed: 42 }); -corpus.artifacts.every((a) => a.warnings.length === 0); // true, all spec-clean +corpus.artifacts.every((a) => a.warnings.length === 0); // true ``` `@cosyte/ncpdp` is an **optional peer dependency**, needed only for the `@cosyte/synth/ncpdp` subpath. @@ -201,7 +201,7 @@ corpus.artifacts.every((a) => a.warnings.length === 0); // true, all spec-clean **Deferred:** vendor-quirk mode. SCRIPT coverage tracks the parser's builder surface: the renewal/change _responses_ land as `@cosyte/ncpdp` grows builders. -## Generate a spec-clean ASTM message +## Generate an ASTM message The `@cosyte/synth/astm` subpath builds ASTM laboratory messages **through `@cosyte/astm`'s own emit surface**: `buildAstmMessage` for the E1394 record layer, `composeAstmFrames` for the E1381 frame @@ -229,7 +229,7 @@ astmFramedRoundTrip(generateAstmResultFramed({ seed: 12345 })).specClean; // tru // Or a reproducible mixed corpus (a result report + an order): const corpus = astmCorpus({ seed: 42 }); -corpus.artifacts.every((a) => a.warnings.length === 0); // true, all spec-clean +corpus.artifacts.every((a) => a.warnings.length === 0); // true ``` `@cosyte/astm` is an **optional peer dependency**, needed only for the `@cosyte/synth/astm` subpath. @@ -276,7 +276,7 @@ vendor-attributed corpus** to ground. ## Co-validate with `@cosyte/deid` (the pairing loop) The `@cosyte/synth/deid` subpath is a deterministic **closed-loop co-validation harness** for the -`synth` ⇄ `deid` pair: it **generates** a spec-clean artifact, **plants** distinctive synthetic PHI +`synth` ⇄ `deid` pair: it **generates** an artifact, **plants** distinctive synthetic PHI sentinels at the patient loci, **de-identifies** it through `@cosyte/deid`, and **verifies** every sentinel is gone from the output (a surviving sentinel is a hard failure) while the clinical payload survives (the over-scrub guard). @@ -332,8 +332,8 @@ isSyntheticNpi(safe.npi(rng)); // true, always a deliberately-invalid-Luhn NPI ( phones, RFC 2606/6761 `example.*` domains, RFC 5737/3849 TEST-NET IPs, a synthetic assigning authority for MRNs). A CI gate proves it. **No generated value can be real or plausibly-real PHI.** -- **Spec-clean by the parser's own judgment**, built through the parser's conservative serializer, and - checked by feeding the artifact straight back in: a spec-clean artifact re-parses with zero warnings. +- **Checked by the parser's own judgment**, built through the parser's conservative serializer and + fed straight back in: each artifact re-parses with zero warnings. - **Deterministic**, a hand-rolled seeded PRNG (`sfc32`/`splitmix32`); `Math.random` is lint-banned. A seed, and only the seed, determines the output, byte-for-byte, anywhere. - **Immutable**, generated artifacts and the `Corpus` result are deep-frozen. diff --git a/docs-content/concepts-archetype.md b/docs-content/concepts-archetype.md index 5bcd7de..051b329 100644 --- a/docs-content/concepts-archetype.md +++ b/docs-content/concepts-archetype.md @@ -27,11 +27,10 @@ const rng = createRng(1); [isSyntheticSsn(safe.ssn(rng)), isSyntheticPhone(safe.phone(rng))]; // => [true, true] ``` -## Spec-clean, by the parser's own judgment +## Checked by the parser's own judgment `synth` never hand-writes bytes. It builds **through the parser's own conservative serializer**, so an -artifact is spec-clean by the exact mechanism the parser already proves, and its correctness is -checkable by feeding it straight back into that parser. A spec-clean artifact re-parses with **zero +artifact is checkable by feeding it straight back into that parser: it re-parses with **zero warnings** and re-serializes byte-identically: ```ts runnable @@ -55,7 +54,7 @@ pipeline without defensive copying. ## Stable fatal codes A generator has no input to tolerate, so its diagnostics are **fatal**: a request it cannot honor -spec-clean (an unsupported format or quirk) throws a typed `SynthError` carrying a stable +(an unsupported format or quirk) throws a typed `SynthError` carrying a stable `SYNTH_FATAL_CODES` value, never a silent fabrication. Codes are `key === value`, so the full set survives an `Object.values(...)` snapshot into a stability tripwire. diff --git a/docs-content/guides-astm.md b/docs-content/guides-astm.md index 9294c9f..70e4dce 100644 --- a/docs-content/guides-astm.md +++ b/docs-content/guides-astm.md @@ -8,8 +8,7 @@ sidebar_position: 7 The `@cosyte/synth/astm` subpath builds ASTM laboratory messages **through `@cosyte/astm`'s own emit surface**: `buildAstmMessage` for the E1394 record layer and `composeAstmFrames` for the E1381 frame -layer, so every message is **spec-clean by construction** and round-trips through the parser with -**zero warnings**. `@cosyte/astm` is an **optional peer dependency**, needed only for this subpath. +layer, so every message round-trips through the parser with **zero warnings**. `@cosyte/astm` is an **optional peer dependency**, needed only for this subpath. The surface covers both layers: @@ -27,10 +26,10 @@ PHI. The practice- and lab-assigned IDs are minted independently, so they stay * `@cosyte/astm` keeps them distinct on parse). `synth` is a **format/conformance generator, not a clinical simulator**: a generated result pairs a code and a value with no claim of clinical coherence. -## A result report, spec-clean by construction +## A result report -The round-trip harness proves spec-cleanliness by `@cosyte/astm`'s own judgment: a spec-clean message -re-parses with zero warnings and re-serializes byte-identically: +The round-trip harness checks a message by `@cosyte/astm`'s own judgment: it re-parses with zero +warnings and re-serializes byte-identically: ```ts runnable import { generateAstmResult, astmRoundTrip } from "@cosyte/synth/astm"; diff --git a/docs-content/guides-deid.md b/docs-content/guides-deid.md index 0076a1d..8698870 100644 --- a/docs-content/guides-deid.md +++ b/docs-content/guides-deid.md @@ -10,7 +10,7 @@ A synthetic-fixture generator and a de-identifier are natural partners: `@cosyte that **looks like** PHI but contains none, and `@cosyte/deid` removes PHI. The `@cosyte/synth/deid` subpath closes the loop between them, a deterministic, seeded **co-validation harness**: -1. **Generate** a spec-clean synthetic artifact through `synth`'s own generators. +1. **Generate** a synthetic artifact through `synth`'s own generators. 2. **Enumerate** the distinctive synthetic PHI sentinels `synth` planted at the patient loci. 3. **De-identify** it through `@cosyte/deid`. 4. **Verify** every sentinel is gone from the de-identified output: a surviving sentinel is a hard @@ -74,7 +74,7 @@ locates a locus but fails to strip it is still caught. ## Deterministic and seeded -The loop is a pure function of the seed: the same seed yields the byte-identical spec-clean artifact, +The loop is a pure function of the seed: the same seed yields the byte-identical artifact, the byte-identical de-identified output, and the same sentinel set. ```ts runnable diff --git a/docs-content/guides-ncpdp.md b/docs-content/guides-ncpdp.md index 337e476..1c53c96 100644 --- a/docs-content/guides-ncpdp.md +++ b/docs-content/guides-ncpdp.md @@ -7,8 +7,7 @@ sidebar_position: 6 # Generate NCPDP messages The `@cosyte/synth/ncpdp` subpath builds both NCPDP standards **through `@cosyte/ncpdp`'s own emit -surface**, so every message is **spec-clean by construction** and round-trips through the parser with -**zero warnings**. `@cosyte/ncpdp` is an **optional peer dependency**, needed only for this subpath. +surface**, so every message round-trips through the parser with **zero warnings**. `@cosyte/ncpdp` is an **optional peer dependency**, needed only for this subpath. NCPDP is two structurally unrelated standards under one brand, and the surface covers both: @@ -21,8 +20,8 @@ NCPDP is two structurally unrelated standards under one brand, and the surface c ## A NewRx, spec-clean by construction -The round-trip harness proves spec-cleanliness by `@cosyte/ncpdp`'s own judgment: a spec-clean message -re-parses with zero warnings and re-serializes byte-identically: +The round-trip harness checks a message by `@cosyte/ncpdp`'s own judgment: it re-parses with zero +warnings and re-serializes byte-identically: ```ts runnable import { generateNewRx, scriptRoundTrip } from "@cosyte/synth/ncpdp"; diff --git a/docs-content/guides-overview.md b/docs-content/guides-overview.md index efbf2f0..9cefcd3 100644 --- a/docs-content/guides-overview.md +++ b/docs-content/guides-overview.md @@ -15,7 +15,7 @@ to one real fixture-generation question. > `@cosyte/ccda`'s `buildCcda`, the [C-CDA guide](./guides-ccda)); X12 005010 (837P/I/D, 835, 271 via > `@cosyte/x12`, the [X12 guide](./guides-x12)); NCPDP (SCRIPT + Telecom via `@cosyte/ncpdp`, the > [NCPDP guide](./guides-ncpdp)); and ASTM (E1394 records + E1381 framing via `@cosyte/astm`, the -> [ASTM guide](./guides-astm)), the spec-clean generation core across all six formats. On top of it, +> [ASTM guide](./guides-astm)), the generation core across all six formats. On top of it, > **vendor-quirk generation** for HL7 v2, C-CDA, and ASTM (see the [quirk guide](./guides-quirks)). A > guide is only written once the behavior it documents is shipped and its runnable example passes the > doc/code-agreement check. @@ -36,8 +36,8 @@ corpus.seed; // => 1867 ## Verify an artifact round-trips before you trust it -The round-trip harness proves spec-cleanliness by the parser's own judgment: a spec-clean artifact -re-parses with zero warnings and re-serializes byte-identically: +The round-trip harness checks an artifact by the parser's own judgment: it re-parses with zero +warnings and re-serializes byte-identically: ```ts runnable import { generateAdt, roundTrip } from "@cosyte/synth/hl7"; diff --git a/docs-content/guides-quirks.md b/docs-content/guides-quirks.md index 6be880f..7d0d613 100644 --- a/docs-content/guides-quirks.md +++ b/docs-content/guides-quirks.md @@ -11,7 +11,7 @@ a parser tolerates the **realistic vendor deviations** real-world traffic carrie the right diagnostic when it does. That is what quirk mode generates. The load-bearing idea: **the quirk vocabulary _is_ the parsers' own profile systems.** A `synth` quirk -deviates the _structure_ of an otherwise spec-clean message so it round-trips through the parser to +deviates the _structure_ of a message that otherwise re-parses with zero warnings so it round-trips through the parser to **exactly one intended, stable warning code**, the tolerance the corresponding parser profile (`hl7.defineProfile`, `ccda.defineCcdaProfile`, `astm.defineAstmProfile`) encodes. This is the **intended-warning contract**: a quirk fixture is never a fiction, it exercises a documented, coded diff --git a/docs-content/guides-x12.md b/docs-content/guides-x12.md index ed5f19f..cfdaae3 100644 --- a/docs-content/guides-x12.md +++ b/docs-content/guides-x12.md @@ -8,8 +8,8 @@ sidebar_position: 5 The `@cosyte/synth/x12` subpath builds HIPAA **005010** transactions **through `@cosyte/x12`'s domain builders** (`build837P/I/D`, `build835`, `build271`), so the ISA/GS/ST…SE/GE/IEA envelope, the computed -HL spine, the control numbers, and every segment are the builder's own: each transaction is -**spec-clean by construction** and round-trips through `@cosyte/x12` with **zero warnings**. +HL spine, the control numbers, and every segment are the builder's own: each transaction +round-trips through `@cosyte/x12` with **zero warnings**. `@cosyte/x12` is an **optional peer dependency**, needed only for this subpath. The X12 surface emits: @@ -22,8 +22,8 @@ The X12 surface emits: ## A claim, spec-clean by construction -The round-trip harness proves spec-cleanliness by `@cosyte/x12`'s own judgment: a spec-clean -interchange re-parses with zero warnings and re-serializes byte-identically: +The round-trip harness checks an interchange by `@cosyte/x12`'s own judgment: it re-parses with +zero warnings and re-serializes byte-identically: ```ts runnable import { generate837P, roundTrip } from "@cosyte/synth/x12"; diff --git a/docs-content/intro.md b/docs-content/intro.md index 01e0787..9b75769 100644 --- a/docs-content/intro.md +++ b/docs-content/intro.md @@ -6,12 +6,13 @@ sidebar_position: 1 # @cosyte/synth -Generate **deterministic, seedable synthetic healthcare fixtures** (spec-clean HL7 v2, FHIR R4 / -US Core, C-CDA, X12, NCPDP and ASTM) without hand-writing a byte of the wire format, and **without +Generate **deterministic, seedable synthetic healthcare fixtures** (HL7 v2, FHIR R4 / US Core, +C-CDA, X12, NCPDP and ASTM) without hand-writing a byte of the wire format, and **without any chance the "patient" you just generated is a real person**. `@cosyte/synth` is a **consumer** of the cosyte parsers, not a parser. It builds each artifact **through -the parser's own builder/serializer** (so the output is spec-clean by construction) and draws every +the parser's own builder/serializer** (so each artifact re-parses through that parser with zero +warnings) and draws every identifier, name, date, phone, and address from a **guaranteed-non-colliding synthetic source** (SSA never-issued SSNs, NANP `555-01xx` phones, `example.*` domains, TEST-NET IPs, a synthetic assigning authority for MRNs, and a shipped clearly-fake name pool). It is a **format/conformance generator, not a diff --git a/docs-content/limitations.md b/docs-content/limitations.md index c1c5772..a514612 100644 --- a/docs-content/limitations.md +++ b/docs-content/limitations.md @@ -16,15 +16,14 @@ a given release ships; this page is the shape of the whole. ## The promise (narrow, on purpose) -`@cosyte/synth` emits **deterministic, seedable, spec-clean (and, in quirk mode, deliberately -off-spec) synthetic fixtures** across the six Cosyte formats, and **every value it emits is drawn from +`@cosyte/synth` emits **deterministic, seedable synthetic fixtures (and, in quirk mode, deliberately +off-spec ones)** across the six Cosyte formats, and **every value it emits is drawn from a guaranteed-non-colliding synthetic source.** -- **Spec-clean by construction.** Each artifact is built **through the parser's own +- **Built through the parser.** Each artifact is built **through the parser's own builder/serializer** (`@cosyte/hl7`'s `buildMessage`, `@cosyte/fhir`'s model + serializer, - `@cosyte/ccda`'s `buildCcda`, the X12/NCPDP/ASTM domain builders), so it is spec-clean by the same - mechanism that makes the parser's emit side spec-clean, and it is proven by feeding the output - straight back into that parser and asserting **zero warnings**. `synth` never hand-writes wire bytes + `@cosyte/ccda`'s `buildCcda`, the X12/NCPDP/ASTM domain builders), and it is checked by feeding the + output straight back into that parser and asserting **zero warnings**. `synth` never hand-writes wire bytes around a builder. **Who did the proving matters, and it is not the same answer for every format: see [Who checks the output, and who does not](#who-checks-the-output-and-who-does-not) below.** - **Synthetic-by-construction.** There is no code path that can emit a name, identifier, date, phone, @@ -199,7 +198,7 @@ measured. ## Coverage, and what is deferred -The spec-clean generation core is **feature-complete across all six formats**. Quirk mode and the +The generation core is **feature-complete across all six formats**. Quirk mode and the `deid` pairing loop ship for a subset; the honest gaps: - **Vendor-quirk mode** ships for the three richest profile systems: **HL7 v2, C-CDA, ASTM**. Quirk diff --git a/docs-content/troubleshooting.md b/docs-content/troubleshooting.md index 5171942..b05cd33 100644 --- a/docs-content/troubleshooting.md +++ b/docs-content/troubleshooting.md @@ -33,7 +33,7 @@ providers. ## An unsupported request threw A generator has nothing to tolerate, so it **fails closed**. Asking for a format or quirk this build -cannot produce spec-clean throws a typed `SynthError` with a stable `SYNTH_FATAL_CODES` value, never a +cannot produce throws a typed `SynthError` with a stable `SYNTH_FATAL_CODES` value, never a hand-written byte workaround: ```ts runnable throws diff --git a/examples/generate-every-format.ts b/examples/generate-every-format.ts index 8ecb631..3d295c2 100644 --- a/examples/generate-every-format.ts +++ b/examples/generate-every-format.ts @@ -1,5 +1,5 @@ /** - * Generate one spec-clean artifact in each of the other five formats, from a seed, and round-trip + * Generate one artifact in each of the other five formats, from a seed, and round-trip * each through its own parser. * * FHIR R4 / US Core, C-CDA R2.1, X12 005010, NCPDP (SCRIPT and Telecom) and ASTM: each is built