@cosyte/astm 0.0.7 → 0.0.8

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.
package/CHANGELOG.md CHANGED
@@ -129,6 +129,73 @@ phase 8` passes while `Phase 8` reds). An arm keyed on a following digit was wri
129
129
 
130
130
  ### Changed
131
131
 
132
+ - **BREAKING: a profile may no longer tolerate `ASTM_RECORD_UNKNOWN_TYPE`**
133
+ (`ASTM-UNKNOWN-RECORD-REMERGE`). The code moves off the profile safety gate's tolerable
134
+ allow-list and onto the safety-critical set, so `defineAstmProfile({ tolerate: [...] })` naming
135
+ it now throws `AstmProfileDefinitionError` at definition time instead of building a profile, and
136
+ the gate is re-checked when a warning would be downgraded, so a profile assembled as a plain
137
+ object rather than through the factory gets the same answer (it declines to downgrade rather than
138
+ throwing, so a hand-authored profile still parses, it just cannot quiet a safety-critical code).
139
+ `TOLERABLE_CODES` goes from four members to three (`ASTM_NONSTANDARD_DELIMITERS`,
140
+ `ASTM_UNKNOWN_ESCAPE_SEQUENCE`, `ASTM_RECORD_UNINTERPRETED_QUERY_STATUS`) and
141
+ `SAFETY_CRITICAL_CODES` / `isSafetyCriticalCode()` answer accordingly. No built-in profile
142
+ tolerated the code, so nothing in this package changes shape; a consumer profile that named it
143
+ will now fail to define, loudly, at the point of definition.
144
+
145
+ **Why, and it is a wrong-patient path.** A message runs from an `H` header to its `L`
146
+ terminator, and `messages()` decides where one starts by reading each record's **type letter**.
147
+ A header the reader cannot recognize as a header (one carrying a stray leading byte, for
148
+ instance) is surfaced as an unsupported record, opens no message, and the two messages either
149
+ side of it are grouped as one. The merged message pairs a patient with results that arrived
150
+ under a different header. The `ASTM_RECORD_UNKNOWN_TYPE` warning is the entire report that this
151
+ happened, so a profile downgrading it to `PROFILE_QUIRK_APPLIED` quieted the whole signal, and a
152
+ `{ strict: true }` parse then accepted the stream with no objection at all.
153
+
154
+ **The type letter turned out to have two load-bearing readers, not one.** `classifyMessage`
155
+ counts `Q` / `R` / `O` records by the same letter, and the rule that a message carrying a query
156
+ is never read as a result set is stated on that count. An unrecognized `Q` costs a host-query
157
+ request that guarantee: the message reads as `kind: "results"`, and the
158
+ `ASTM_RECORD_AMBIGUOUS_MESSAGE_KIND` warning that flags a query-plus-result contradiction
159
+ disappears along with the `Q` it was counting. There too `ASTM_RECORD_UNKNOWN_TYPE` is the only
160
+ warning left on the stream. Both readers are measured in the regression test. The
161
+ mis-classification itself is not fixed here, for the same reason the merge is not: it is a
162
+ property of reading the letter, and inferring the intended letter is the guess this package
163
+ declines to make.
164
+
165
+ **The variant that reaches furthest carries no second patient.** When the merged second message
166
+ has its own `P`, the merged message holds two and the multi-patient guard throws. When the
167
+ second message is **result-only**, the merged message still holds exactly one `P`, so `patient()`
168
+ and `results()` both answer confidently and the first patient silently acquires the second
169
+ message's results. That is the fixture the regression test pins.
170
+
171
+ **The parser is deliberately unchanged.** Recognizing a mangled header _as_ a header means
172
+ guessing at a byte the sender did not send, and that guess would split a stream a different way
173
+ just as silently. A lenient parse still merges and still warns; a strict parse refuses; and the
174
+ refusal can no longer be configured away. `messages()`, the warning's own message text, the
175
+ `UnsupportedRecord` type, the README and the quickstart all now say to read this code as a
176
+ possible lost message boundary rather than as cosmetic noise.
177
+
178
+ **The admission test for the allow-list gained a second clause**, which is the durable part of
179
+ this change. A code was admitted on one question: can it alter, drop, or fabricate an extracted
180
+ value? `ASTM_RECORD_UNKNOWN_TYPE` still passes that one, and it was still wrong to tolerate,
181
+ because the condition it reports had quietly become something the library reads. The rule is now
182
+ that a code is tolerable only while **nothing else in this package reads the condition the
183
+ warning reports**, and that second clause is a claim about the whole library which can stop being
184
+ true without anyone editing `safety.ts`. It is a review obligation, not a mechanical check, and
185
+ the file says so rather than implying a gate that does not exist. The three surviving codes were
186
+ each re-derived against both readers of record structure, and each is measured by comparing the
187
+ same logical stream with the reported condition present and absent. That is deliberately not a
188
+ comparison of a parse with a profile against one without: the profile transform runs after the
189
+ records are built, so the second comparison is identical for every code and would have passed for
190
+ the one just removed. The comparison actually used is exercised on the mangled-header pair as a
191
+ negative control, where it has to fail.
192
+
193
+ **Evidence, labelled.** The `H` … `L` message unit is _verified primary_ and its grounding is
194
+ recorded on `messages()`, unchanged here. The allow-list itself is **this library's own policy,
195
+ not the standard's**: no clause governs which of our warning codes a profile may downgrade, and
196
+ none is claimed for it. The behaviour above (the merge, the accessors answering, the strict
197
+ acceptance under a tolerating profile) is _measured_, on the tree before and after the change.
198
+
132
199
  - **The em dash (U+2014) is gone from every tracked file, and a CI gate keeps it out**
133
200
  (`EMDASH-CONFORMANCE`). The brand rule bans the character outright across every cosyte surface
134
201
  and names commit messages explicitly; this package was the last one it had not reached, and the
package/README.md CHANGED
@@ -42,11 +42,14 @@ reference parser, [`@cosyte/hl7`](https://github.com/cosyte/hl7).
42
42
  and lost.
43
43
  - **Vendor profiles.** `defineAstmProfile()` builds a provenance-backed profile whose tolerances
44
44
  downgrade _expected_, non-safety-critical deviations to a `PROFILE_QUIRK_APPLIED` warning without
45
- ever altering a value, behind a definition-time safety gate that refuses to tolerate any result
46
- value, flag, status, range, or units warning, any patient or comment context, any message-kind
47
- ambiguity, and any frame or transport integrity warning. A profile can never make a bad checksum
48
- "ok" or a cancelled result read "final." Named per-vendor profiles await a public,
49
- vendor-attributed quirk document.
45
+ ever altering a value, behind a safety gate that refuses to tolerate any result value, flag,
46
+ status, range, or units warning, any patient or comment context, any message-kind ambiguity, any
47
+ unrecognized record type, and any frame or transport integrity warning. The gate runs when a
48
+ profile is defined **and** again when a warning would be downgraded, so a profile assembled as a
49
+ plain object rather than through `defineAstmProfile()` gets the same answer. A profile can never
50
+ make a bad checksum "ok", a cancelled result read "final", or quiet the warning that says a
51
+ message boundary went unrecognized. Named per-vendor profiles await a public, vendor-attributed
52
+ quirk document.
50
53
  - **Terminology, bring your own.** `applyLivd(msg, catalog)` maps an analyzer's local test code to a
51
54
  LOINC from a consumer-supplied IICC LIVD catalog as an additive, advisory annotation that never
52
55
  mutates the raw code or value and never guesses a LOINC. No LOINC, SNOMED, or LIVD dictionary is
@@ -170,6 +173,18 @@ patient is unchanged, and so is a result-only message with no `P` at all, which
170
173
  `undefined`. `commentsFor()` is unchanged on every stream, because the parent record you hand it
171
174
  already names the message.
172
175
 
176
+ Splitting reads each record's type letter, so check for an `ASTM_RECORD_UNKNOWN_TYPE` warning before
177
+ you trust the split. A header the reader does not recognize as a header, one carrying a stray leading
178
+ byte for instance, opens no message, and the messages either side of it merge back into one, so a
179
+ patient can end up holding results that arrived under a different header. Delimiters are re-read at
180
+ each header too, so if the unrecognized one declared a different set, the records after it are read
181
+ with the previous set and their fields can be lost rather than merely misfiled. The
182
+ parser warns on that record and a `{ strict: true }` parse refuses the stream. That warning is the
183
+ only report the merge produces, so a profile is not allowed to tolerate it: the code is refused when
184
+ a profile is defined, and a warning carrying it is not downgraded whatever profile is in force. Do
185
+ not gate on the warning count, though, because the records that merged in can raise warnings of
186
+ their own.
187
+
173
188
  ## Map local codes to LOINC (LIVD, bring-your-own)
174
189
 
175
190
  An analyzer sends a proprietary local test code in the Universal Test ID; a standard LOINC is mapped
package/dist/index.cjs CHANGED
@@ -121,7 +121,11 @@ function primaryCode(u) {
121
121
 
122
122
  // src/common/warnings.ts
123
123
  var WARNING_CODES = {
124
- /** A record's type letter is not one of the modeled types: surfaced as an unsupported record. */
124
+ /**
125
+ * A record's type letter is not one of the modeled types: surfaced as an unsupported record,
126
+ * never dropped. Treat it as a possible lost message boundary, because a header the reader did
127
+ * not recognize as one does not open a new message.
128
+ */
125
129
  ASTM_RECORD_UNKNOWN_TYPE: "ASTM_RECORD_UNKNOWN_TYPE",
126
130
  /** The header declared delimiters other than the canonical `H|\^&`: tolerated, noted. */
127
131
  ASTM_NONSTANDARD_DELIMITERS: "ASTM_NONSTANDARD_DELIMITERS",
@@ -214,7 +218,7 @@ var WARNING_CODES = {
214
218
  function unknownRecordType(position) {
215
219
  return {
216
220
  code: WARNING_CODES.ASTM_RECORD_UNKNOWN_TYPE,
217
- message: "Unrecognized record type, surfaced verbatim as an unsupported record.",
221
+ message: "Unrecognized record type, surfaced verbatim as an unsupported record. If this record was a header, message grouping did not open a new message here.",
218
222
  position
219
223
  };
220
224
  }
@@ -427,6 +431,135 @@ function classifyMessage(records) {
427
431
  return { kind, hasQuery, hasResults, hasOrders, isHostQueryRequest: kind === "host-query" };
428
432
  }
429
433
 
434
+ // src/frames/warnings.ts
435
+ var FRAME_WARNING_CODES = {
436
+ /**
437
+ * A frame's two-hex-char checksum did not match the modulo-256 sum recomputed over its bytes. The
438
+ * frame is surfaced with `trusted: false` and its text is **never merged** into a reassembled
439
+ * record (default **warn** in lenient mode, escalated to a thrown error in `strict`). Corruption is
440
+ * never silently trusted: the "checksums are routinely not validated" claim was refuted; we
441
+ * validate.
442
+ */
443
+ ASTM_FRAME_BAD_CHECKSUM: "ASTM_FRAME_BAD_CHECKSUM",
444
+ /**
445
+ * A frame's sequence number was not the expected next value (`1 → … → 7 → 0 → …`): a frame was
446
+ * possibly dropped. The stream is **never silently concatenated across the gap** as if contiguous;
447
+ * the in-progress record is tainted and not emitted as a clean reassembly.
448
+ */
449
+ ASTM_FRAME_SEQUENCE_GAP: "ASTM_FRAME_SEQUENCE_GAP",
450
+ /**
451
+ * A frame opened with `STX` but no valid terminator + checksum was found before the stream ended
452
+ * (or before the next `STX`), or a record's frames ended on an intermediate `ETB` with no final
453
+ * `ETX`. The partial bytes are surfaced flagged untrusted and **no partial record is invented**
454
+ * (warn in lenient, thrown in `strict`).
455
+ */
456
+ ASTM_FRAME_UNTERMINATED: "ASTM_FRAME_UNTERMINATED",
457
+ /**
458
+ * A frame's record text exceeded the 240-byte limit without a split. The frame is still surfaced
459
+ * (and, if its checksum validates, reassembled): the deviation is flagged, not silently dropped
460
+ * (warn in lenient, thrown in `strict`).
461
+ */
462
+ ASTM_FRAME_OVERSIZE: "ASTM_FRAME_OVERSIZE"
463
+ };
464
+ function frameBadChecksum(position) {
465
+ return {
466
+ code: FRAME_WARNING_CODES.ASTM_FRAME_BAD_CHECKSUM,
467
+ message: "Frame checksum mismatch, surfaced untrusted, never merged into a record.",
468
+ position
469
+ };
470
+ }
471
+ function frameSequenceGap(position) {
472
+ return {
473
+ code: FRAME_WARNING_CODES.ASTM_FRAME_SEQUENCE_GAP,
474
+ message: "Frame number out of sequence, possible dropped frame, never silently bridged.",
475
+ position
476
+ };
477
+ }
478
+ function frameUnterminated(position) {
479
+ return {
480
+ code: FRAME_WARNING_CODES.ASTM_FRAME_UNTERMINATED,
481
+ message: "Unterminated frame, partial bytes surfaced untrusted, no partial record invented.",
482
+ position
483
+ };
484
+ }
485
+ function frameOversize(position) {
486
+ return {
487
+ code: FRAME_WARNING_CODES.ASTM_FRAME_OVERSIZE,
488
+ message: "Frame text exceeded the 240-byte limit without a split, flagged, never dropped.",
489
+ position
490
+ };
491
+ }
492
+
493
+ // src/ltp/warnings.ts
494
+ var LTP_WARNING_CODES = {
495
+ /**
496
+ * The transport detector could not tell a framed stream from a raw (unframed) one from its leading
497
+ * byte: it was neither `STX`/`ENQ` nor a bare record letter. It **defaults to framed** and warns,
498
+ * never guessing silently into data loss; a profile override forces the mode. (cobas b121 drops
499
+ * framing over TCP; cobas 4800 / Iguana retain it, both realities exist, so an unrecognizable lead
500
+ * is defaulted, not assumed.)
501
+ */
502
+ ASTM_LTP_AMBIGUOUS_TRANSPORT: "ASTM_LTP_AMBIGUOUS_TRANSPORT",
503
+ /**
504
+ * A control event arrived in a protocol state that did not expect it: e.g. an inbound `ACK`/`NAK`
505
+ * at a receiver (which sends, never receives, those), or an `ENQ` mid-transfer. The event is
506
+ * surfaced and handled defensively (an unexpected `ACK`/`NAK` is **never** read as acceptance of
507
+ * data); it never advances the transfer as if valid.
508
+ */
509
+ ASTM_LTP_UNEXPECTED_EVENT: "ASTM_LTP_UNEXPECTED_EVENT",
510
+ /**
511
+ * The receiver rejected a received frame with a `NAK` instead of accepting it: because its
512
+ * checksum failed, it was unterminated, or its frame number was out of sequence. The frame's text
513
+ * is **never** appended to the record and the transfer does **not** advance; the receiver awaits the
514
+ * sender's retransmit. This is the protocol-level face of the frame codec's fail-safe: a bad frame
515
+ * drives retransmit, not acceptance.
516
+ */
517
+ ASTM_LTP_FRAME_REJECTED: "ASTM_LTP_FRAME_REJECTED"
518
+ };
519
+ function ltpAmbiguousTransport() {
520
+ return {
521
+ code: LTP_WARNING_CODES.ASTM_LTP_AMBIGUOUS_TRANSPORT,
522
+ message: "Leading byte was neither a frame start (STX/ENQ) nor a record letter, defaulted to framed; override with a profile to force raw."
523
+ };
524
+ }
525
+ function ltpUnexpectedEvent(frameNumber) {
526
+ return {
527
+ code: LTP_WARNING_CODES.ASTM_LTP_UNEXPECTED_EVENT,
528
+ message: "Control event arrived in a state that did not expect it, handled defensively, never read as acceptance.",
529
+ ...frameNumber !== void 0 ? { frameNumber } : {}
530
+ };
531
+ }
532
+ function ltpFrameRejected(frameNumber) {
533
+ return {
534
+ code: LTP_WARNING_CODES.ASTM_LTP_FRAME_REJECTED,
535
+ message: "Frame rejected (bad checksum, unterminated, or out of sequence), NAK sent, retransmit expected, never accepted.",
536
+ ...frameNumber !== void 0 ? { frameNumber } : {}
537
+ };
538
+ }
539
+
540
+ // src/profiles/safety.ts
541
+ var TOLERABLE_CODES = Object.freeze(
542
+ /* @__PURE__ */ new Set([
543
+ WARNING_CODES.ASTM_NONSTANDARD_DELIMITERS,
544
+ WARNING_CODES.ASTM_UNKNOWN_ESCAPE_SEQUENCE,
545
+ WARNING_CODES.ASTM_RECORD_UNINTERPRETED_QUERY_STATUS
546
+ ])
547
+ );
548
+ var ALL_WARNING_CODES = [
549
+ ...Object.values(WARNING_CODES),
550
+ ...Object.values(FRAME_WARNING_CODES),
551
+ ...Object.values(LTP_WARNING_CODES)
552
+ ];
553
+ var ALL_ASTM_WARNING_CODES = Object.freeze(
554
+ new Set(ALL_WARNING_CODES)
555
+ );
556
+ var SAFETY_CRITICAL_CODES = Object.freeze(
557
+ new Set(ALL_WARNING_CODES.filter((c) => !TOLERABLE_CODES.has(c)))
558
+ );
559
+ function isSafetyCriticalCode(code) {
560
+ return SAFETY_CRITICAL_CODES.has(code);
561
+ }
562
+
430
563
  // src/profiles/apply.ts
431
564
  function toleranceApplies(tolerance, warning) {
432
565
  if (tolerance.code !== warning.code) return false;
@@ -442,6 +575,7 @@ function toleranceApplies(tolerance, warning) {
442
575
  }
443
576
  function applyAstmProfile(profile, warning) {
444
577
  if (warning.expected === true) return warning;
578
+ if (isSafetyCriticalCode(warning.code)) return warning;
445
579
  for (const tolerance of profile.tolerate) {
446
580
  if (toleranceApplies(tolerance, warning)) {
447
581
  return profileQuirkApplied(warning, profile.name);
@@ -563,136 +697,6 @@ var AstmProfileDefinitionError = class extends Error {
563
697
  }
564
698
  };
565
699
 
566
- // src/frames/warnings.ts
567
- var FRAME_WARNING_CODES = {
568
- /**
569
- * A frame's two-hex-char checksum did not match the modulo-256 sum recomputed over its bytes. The
570
- * frame is surfaced with `trusted: false` and its text is **never merged** into a reassembled
571
- * record (default **warn** in lenient mode, escalated to a thrown error in `strict`). Corruption is
572
- * never silently trusted: the "checksums are routinely not validated" claim was refuted; we
573
- * validate.
574
- */
575
- ASTM_FRAME_BAD_CHECKSUM: "ASTM_FRAME_BAD_CHECKSUM",
576
- /**
577
- * A frame's sequence number was not the expected next value (`1 → … → 7 → 0 → …`): a frame was
578
- * possibly dropped. The stream is **never silently concatenated across the gap** as if contiguous;
579
- * the in-progress record is tainted and not emitted as a clean reassembly.
580
- */
581
- ASTM_FRAME_SEQUENCE_GAP: "ASTM_FRAME_SEQUENCE_GAP",
582
- /**
583
- * A frame opened with `STX` but no valid terminator + checksum was found before the stream ended
584
- * (or before the next `STX`), or a record's frames ended on an intermediate `ETB` with no final
585
- * `ETX`. The partial bytes are surfaced flagged untrusted and **no partial record is invented**
586
- * (warn in lenient, thrown in `strict`).
587
- */
588
- ASTM_FRAME_UNTERMINATED: "ASTM_FRAME_UNTERMINATED",
589
- /**
590
- * A frame's record text exceeded the 240-byte limit without a split. The frame is still surfaced
591
- * (and, if its checksum validates, reassembled): the deviation is flagged, not silently dropped
592
- * (warn in lenient, thrown in `strict`).
593
- */
594
- ASTM_FRAME_OVERSIZE: "ASTM_FRAME_OVERSIZE"
595
- };
596
- function frameBadChecksum(position) {
597
- return {
598
- code: FRAME_WARNING_CODES.ASTM_FRAME_BAD_CHECKSUM,
599
- message: "Frame checksum mismatch, surfaced untrusted, never merged into a record.",
600
- position
601
- };
602
- }
603
- function frameSequenceGap(position) {
604
- return {
605
- code: FRAME_WARNING_CODES.ASTM_FRAME_SEQUENCE_GAP,
606
- message: "Frame number out of sequence, possible dropped frame, never silently bridged.",
607
- position
608
- };
609
- }
610
- function frameUnterminated(position) {
611
- return {
612
- code: FRAME_WARNING_CODES.ASTM_FRAME_UNTERMINATED,
613
- message: "Unterminated frame, partial bytes surfaced untrusted, no partial record invented.",
614
- position
615
- };
616
- }
617
- function frameOversize(position) {
618
- return {
619
- code: FRAME_WARNING_CODES.ASTM_FRAME_OVERSIZE,
620
- message: "Frame text exceeded the 240-byte limit without a split, flagged, never dropped.",
621
- position
622
- };
623
- }
624
-
625
- // src/ltp/warnings.ts
626
- var LTP_WARNING_CODES = {
627
- /**
628
- * The transport detector could not tell a framed stream from a raw (unframed) one from its leading
629
- * byte: it was neither `STX`/`ENQ` nor a bare record letter. It **defaults to framed** and warns,
630
- * never guessing silently into data loss; a profile override forces the mode. (cobas b121 drops
631
- * framing over TCP; cobas 4800 / Iguana retain it, both realities exist, so an unrecognizable lead
632
- * is defaulted, not assumed.)
633
- */
634
- ASTM_LTP_AMBIGUOUS_TRANSPORT: "ASTM_LTP_AMBIGUOUS_TRANSPORT",
635
- /**
636
- * A control event arrived in a protocol state that did not expect it: e.g. an inbound `ACK`/`NAK`
637
- * at a receiver (which sends, never receives, those), or an `ENQ` mid-transfer. The event is
638
- * surfaced and handled defensively (an unexpected `ACK`/`NAK` is **never** read as acceptance of
639
- * data); it never advances the transfer as if valid.
640
- */
641
- ASTM_LTP_UNEXPECTED_EVENT: "ASTM_LTP_UNEXPECTED_EVENT",
642
- /**
643
- * The receiver rejected a received frame with a `NAK` instead of accepting it: because its
644
- * checksum failed, it was unterminated, or its frame number was out of sequence. The frame's text
645
- * is **never** appended to the record and the transfer does **not** advance; the receiver awaits the
646
- * sender's retransmit. This is the protocol-level face of the frame codec's fail-safe: a bad frame
647
- * drives retransmit, not acceptance.
648
- */
649
- ASTM_LTP_FRAME_REJECTED: "ASTM_LTP_FRAME_REJECTED"
650
- };
651
- function ltpAmbiguousTransport() {
652
- return {
653
- code: LTP_WARNING_CODES.ASTM_LTP_AMBIGUOUS_TRANSPORT,
654
- message: "Leading byte was neither a frame start (STX/ENQ) nor a record letter, defaulted to framed; override with a profile to force raw."
655
- };
656
- }
657
- function ltpUnexpectedEvent(frameNumber) {
658
- return {
659
- code: LTP_WARNING_CODES.ASTM_LTP_UNEXPECTED_EVENT,
660
- message: "Control event arrived in a state that did not expect it, handled defensively, never read as acceptance.",
661
- ...frameNumber !== void 0 ? { frameNumber } : {}
662
- };
663
- }
664
- function ltpFrameRejected(frameNumber) {
665
- return {
666
- code: LTP_WARNING_CODES.ASTM_LTP_FRAME_REJECTED,
667
- message: "Frame rejected (bad checksum, unterminated, or out of sequence), NAK sent, retransmit expected, never accepted.",
668
- ...frameNumber !== void 0 ? { frameNumber } : {}
669
- };
670
- }
671
-
672
- // src/profiles/safety.ts
673
- var TOLERABLE_CODES = Object.freeze(
674
- /* @__PURE__ */ new Set([
675
- WARNING_CODES.ASTM_RECORD_UNKNOWN_TYPE,
676
- WARNING_CODES.ASTM_NONSTANDARD_DELIMITERS,
677
- WARNING_CODES.ASTM_UNKNOWN_ESCAPE_SEQUENCE,
678
- WARNING_CODES.ASTM_RECORD_UNINTERPRETED_QUERY_STATUS
679
- ])
680
- );
681
- var ALL_WARNING_CODES = [
682
- ...Object.values(WARNING_CODES),
683
- ...Object.values(FRAME_WARNING_CODES),
684
- ...Object.values(LTP_WARNING_CODES)
685
- ];
686
- var ALL_ASTM_WARNING_CODES = Object.freeze(
687
- new Set(ALL_WARNING_CODES)
688
- );
689
- var SAFETY_CRITICAL_CODES = Object.freeze(
690
- new Set(ALL_WARNING_CODES.filter((c) => !TOLERABLE_CODES.has(c)))
691
- );
692
- function isSafetyCriticalCode(code) {
693
- return SAFETY_CRITICAL_CODES.has(code);
694
- }
695
-
696
700
  // src/profiles/validate.ts
697
701
  var KNOWN_OPTION_KEYS = [
698
702
  "name",
@@ -772,7 +776,7 @@ function validateTolerations(tolerate, profileName) {
772
776
  }
773
777
  if (isSafetyCriticalCode(t.code)) {
774
778
  throw new AstmProfileDefinitionError(
775
- `Profile '${profileName}' may not tolerate '${t.code}': it is a safety-critical warning code (a result value / flag / status / range / units, patient or comment context, message-kind ambiguity, code system, or a frame / LTP integrity warning). A profile quiets benign structural noise, never a deviation that could change a clinical reading or corrupt the wire: it can never make a bad checksum "ok" or a cancelled result read "final."`,
779
+ `Profile '${profileName}' may not tolerate '${t.code}': it is a safety-critical warning code (a result value / flag / status / range / units, patient or comment context, message-kind ambiguity, code system, an unrecognized record type, or a frame / LTP integrity warning). A profile quiets benign structural noise, never a deviation that could change a clinical reading, report a lost message boundary, or corrupt the wire: it can never make a bad checksum "ok", a cancelled result read "final", or quiet the warning that says two messages were read as one.`,
776
780
  profileName
777
781
  );
778
782
  }
@@ -2199,7 +2203,7 @@ function concatBytes3(chunks) {
2199
2203
  }
2200
2204
 
2201
2205
  // src/index.ts
2202
- var VERSION = "0.0.7";
2206
+ var VERSION = "0.0.8";
2203
2207
 
2204
2208
  exports.ALL_ASTM_WARNING_CODES = ALL_ASTM_WARNING_CODES;
2205
2209
  exports.AMBIGUOUS_CODES = AMBIGUOUS_CODES;