@cosyte/x12 0.0.14 → 0.0.15

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/dist/index.d.cts CHANGED
@@ -2483,9 +2483,10 @@ declare function unescapeRelease(input: string, delimiters: Delimiters, emit: (w
2483
2483
  * the untyped-refusal defect this package has fixed elsewhere. This is a pure
2484
2484
  * text utility with no spec, no element and no caller context to name, so
2485
2485
  * `TypeError` is the accurate answer for a wrong-typed argument. **Nothing
2486
- * inside this library can reach it**: all nine builders route every element
2486
+ * inside this library can reach it**: every builder routes its elements
2487
2487
  * through `src/builder/caller-string.ts`, which refuses first with the calling
2488
- * builder's own typed, code-tagged error. This throw is the backstop for a
2488
+ * builder's own typed, code-tagged error. (No count: it is asserted by
2489
+ * `test/builder-string-type.test.ts` and was stale here.) This throw is the backstop for a
2489
2490
  * consumer calling the export directly, where the alternative was silent data
2490
2491
  * loss.
2491
2492
  *
@@ -5720,22 +5721,23 @@ declare function get837Claims(delimiters: Delimiters, tx: X12TransactionSet, opt
5720
5721
 
5721
5722
  /**
5722
5723
  * Interchange + group + transaction identity for the built 837. The builder
5723
- * fixes GS-01 to `"HC"` and the ST-03 / GS-08 version to the variant's TR3
5724
- * (`005010X222A2` / `X223A3` / `X224A2`) so the caller never hand-codes them.
5725
- *
5726
- * **🩺 Known limitation, disclosed rather than changed: those three are
5727
- * published errata guides, but they are neither the identifiers HIPAA
5728
- * adopts at 45 CFR 162.1102 nor the ones payer companion guides commonly
5729
- * require in ST-03 / GS-08** (CMS and several state Medicaid guides state
5730
- * `005010X222A1` for Professional, `005010X223A2` for Institutional and
5731
- * `005010X224A2` for Dental). **A partner that requires one of those will
5732
- * reject a Professional or Institutional 837 this builder emits, and there
5733
- * is currently no way for a caller to override the value.** Nothing here
5734
- * was re-stamped on that evidence: which published guide identifier a
5735
- * trading partner accepts is a partner fact, not a spec fact, and silently
5736
- * changing bytes this library already emitted would break the partners it
5737
- * works with today. `KNOWN-LIMITATIONS.md` carries this as an open
5738
- * residual. The READ side is unaffected - `get837Claims` recognises all of
5724
+ * fixes GS-01 to `"HC"`, and defaults the ST-03 / GS-08 reference to the
5725
+ * variant's TR3 (`005010X222A2` / `X223A3` / `X224A2`) so the caller never
5726
+ * has to hand-code it.
5727
+ *
5728
+ * **🩺 That default is not what every trading partner accepts, so
5729
+ * {@link Build837EnvelopeSpec.implementationConventionReference} overrides
5730
+ * it.** The three defaults are published errata guides, but they are
5731
+ * neither the identifiers HIPAA adopts at 45 CFR 162.1102 nor the ones
5732
+ * payer companion guides commonly require in ST-03 / GS-08 (CMS and several
5733
+ * state Medicaid guides state `005010X222A1` for Professional and
5734
+ * `005010X223A2` for Institutional). **A partner that requires one of those
5735
+ * will reject a Professional or Institutional 837 built on the default**,
5736
+ * and the override is how you send what your partner asked for. The default
5737
+ * itself was deliberately NOT re-stamped: which published guide identifier
5738
+ * a partner accepts is a partner fact rather than a spec fact, and changing
5739
+ * bytes this library already emitted would break the partners it works with
5740
+ * today. The READ side is unaffected - `get837Claims` recognises all of
5739
5741
  * these references.
5740
5742
  *
5741
5743
  * @example
@@ -5764,6 +5766,44 @@ interface Build837EnvelopeSpec {
5764
5766
  readonly groupControlNumber: string;
5765
5767
  /** ST-02 / SE-02 - transaction set control number. */
5766
5768
  readonly transactionSetControlNumber: string;
5769
+ /**
5770
+ * 🩺 ST-03 **and** GS-08 - the implementation convention reference this
5771
+ * 837 declares. Default: the variant's TR3 (`005010X222A2` Professional,
5772
+ * `005010X223A3` Institutional, `005010X224A2` Dental).
5773
+ *
5774
+ * **Set it to whatever your trading partner's companion guide requires**,
5775
+ * for example `005010X222A1` on a professional claim to a payer that asks
5776
+ * for it. Which published identifier a partner accepts is a partner fact,
5777
+ * so this library will not choose for you: it defaults to a real published
5778
+ * guide and gets out of the way. **One value is written to both elements**,
5779
+ * because this builder has always written the same reference to ST-03 and
5780
+ * GS-08 and nothing grounds a caller making them differ. That is a statement
5781
+ * about the bytes this field emits, not about what each element may legally
5782
+ * hold: GS-08 is data element 480 (`AN 1/12`) and ST-03 is element 1705
5783
+ * (`AN 1/35`), and nothing here bounds the length.
5784
+ *
5785
+ * Refused, all `X12_837_BUILD_INVALID_SPEC`. An **empty** string, because a
5786
+ * trailing empty element is dropped on emit, so it would delete ST-03 and
5787
+ * GS-08 rather than send them empty. One carrying an **active delimiter or
5788
+ * the release character**, because these two elements cannot carry it even
5789
+ * escaped: the ST and GS segments are read by a splitter that is not
5790
+ * release-aware, so the declaration would silently become two elements. And
5791
+ * one **this library's own reader resolves to a different variant**
5792
+ * (`005010X223A2` handed to `build837P`): the file would declare one variant
5793
+ * and carry another's service segments, and `get837Claims` would then decode
5794
+ * none of its service lines. Those are what this field adds, on top of the
5795
+ * element-type guard every string slot already has, which refuses a
5796
+ * non-string with the same code - no total is published. **Anything else is
5797
+ * emitted as given** - the set of published errata is not provably
5798
+ * exhaustive, so an identifier this library does not carry is the caller's
5799
+ * call, not an error.
5800
+ *
5801
+ * 🩺 A guard on this element cannot make the element trustworthy. An active
5802
+ * delimiter in a DIFFERENT envelope field splits its own segment and shifts
5803
+ * every element after it, so ST-03 / GS-08 are then read out of a
5804
+ * neighbour's slot. `KNOWN-LIMITATIONS.md` carries the measurement.
5805
+ */
5806
+ readonly implementationConventionReference?: string;
5767
5807
  /** ISA-05 - interchange sender qualifier. Default `"ZZ"`. */
5768
5808
  readonly senderQualifier?: string;
5769
5809
  /** ISA-07 - interchange receiver qualifier. Default `"ZZ"`. */
@@ -6475,8 +6515,9 @@ interface Build837Spec {
6475
6515
 
6476
6516
  /**
6477
6517
  * `build837P` / `build837I` / `build837D` - pure-function builders for a
6478
- * 005010 837 Healthcare Claim (Professional `X222A2`, Institutional
6479
- * `X223A3`, Dental `X224A2`). NEVER auto-sends, NEVER opens a socket, NEVER
6518
+ * 005010 837 Healthcare Claim (Professional, Institutional, Dental; the
6519
+ * ST-03 / GS-08 guide reference defaults to `X222A2` / `X223A3` / `X224A2`
6520
+ * and the caller may state another). NEVER auto-sends, NEVER opens a socket, NEVER
6480
6521
  * touches the filesystem. The library mechanically emits the claim it is
6481
6522
  * told; a spec whose billing-provider → subscriber → (claims | patient)
6482
6523
  * tree cannot form a valid HL hierarchy is REFUSED via {@link
@@ -6505,7 +6546,9 @@ interface Build837Spec {
6505
6546
  */
6506
6547
 
6507
6548
  /**
6508
- * `build837P` - assemble a 005010X222A2 Professional 837 around the spec.
6549
+ * `build837P` - assemble a Professional 837 around the spec, declaring
6550
+ * `005010X222A2` unless `envelope.implementationConventionReference` states
6551
+ * the guide your trading partner requires.
6509
6552
  *
6510
6553
  * @example
6511
6554
  * ```ts
@@ -6537,8 +6580,10 @@ interface Build837Spec {
6537
6580
  */
6538
6581
  declare function build837P(spec: Build837Spec): X12Interchange;
6539
6582
  /**
6540
- * `build837I` - assemble a 005010X223A3 Institutional 837 around the spec.
6541
- * Service lines must be `variant: "I"` (SV2).
6583
+ * `build837I` - assemble an Institutional 837 around the spec, declaring
6584
+ * `005010X223A3` unless `envelope.implementationConventionReference` states
6585
+ * the guide your trading partner requires. Service lines must be
6586
+ * `variant: "I"` (SV2).
6542
6587
  *
6543
6588
  * @example
6544
6589
  * ```ts
@@ -6549,8 +6594,10 @@ declare function build837P(spec: Build837Spec): X12Interchange;
6549
6594
  */
6550
6595
  declare function build837I(spec: Build837Spec): X12Interchange;
6551
6596
  /**
6552
- * `build837D` - assemble a 005010X224A2 Dental 837 around the spec. Service
6553
- * lines must be `variant: "D"` (SV3); per-line tooth detail rides on TOO.
6597
+ * `build837D` - assemble a Dental 837 around the spec, declaring
6598
+ * `005010X224A2` unless `envelope.implementationConventionReference` states
6599
+ * the guide your trading partner requires. Service lines must be
6600
+ * `variant: "D"` (SV3); per-line tooth detail rides on TOO.
6554
6601
  *
6555
6602
  * @example
6556
6603
  * ```ts
@@ -12862,6 +12909,82 @@ declare function build999(spec: Build999Spec): X12Interchange;
12862
12909
  * library does NOT silently invent envelope bytes around it - the caller's
12863
12910
  * application boundary owns whether the TA1 is embedded in an outbound
12864
12911
  * interchange or sent as a standalone TA1-only interchange.
12912
+ *
12913
+ * ## 🩺 Why every element is released, and what that changed
12914
+ *
12915
+ * `raw` used to be `[...five caller values].join(elementSeparator)` with
12916
+ * nothing in between, so a caller value carrying an active delimiter took
12917
+ * a slot of its own and shifted every element after it down one. TA1-04 is
12918
+ * the disposition and TA1-05 the note, so the shift landed the read on the
12919
+ * wrong pair, and `parseTA1` narrows an out-of-enum TA1-04 to `R`:
12920
+ * **an Accept this library emitted read back as a Reject**, with the TA1-01
12921
+ * reassociation key merged into TA1-02 and `warnings: []` on every channel.
12922
+ * The inverse is the less safe one and also existed: a `noteCode` of
12923
+ * literally `"A"` (a value the type forbids and nothing checks at run time)
12924
+ * shifted onto TA1-04 and made a **Reject read back as an Accept**, which a
12925
+ * sender never resubmits against.
12926
+ *
12927
+ * The grounding is inside the package, not in a spec clause, which is the
12928
+ * same tiebreak `X12-ENVELOPE-SPLITTER-NOT-RELEASE-AWARE` recorded: one
12929
+ * function disagreed with itself. This module emitted bytes that this
12930
+ * package's own reader decoded into a different disposition than the one
12931
+ * the caller asked for, and every other builder already released the same
12932
+ * class of element through the same helper.
12933
+ *
12934
+ * **It changes bytes, and that is the cost that kept it open for a slice.**
12935
+ * A value containing none of the four delimiters or the release character
12936
+ * is emitted byte-for-byte as before, which is every conformant TA1. A
12937
+ * value containing one is now released, so its bytes differ from the ones
12938
+ * `0.0.14` and earlier put on the wire. What that costs is stated outright
12939
+ * below rather than argued away, and **without a total**: two drafts of this
12940
+ * account published a closed one and both were refuted.
12941
+ *
12942
+ * - **The consumer predicate moves in BOTH directions.** Read the property
12943
+ * rather than a direction list: `parseTA1` of a `buildTA1` output now
12944
+ * reports the disposition and note the CALLER passed, where before it
12945
+ * reported whatever element the shift left in TA1-04. So
12946
+ * `ackCode === "R"` stops firing where an Accept had been shifted onto
12947
+ * it, and starts firing where a Reject had been shifted off it -
12948
+ * `interchangeTime: "12*A"` with `ackCode: "R"` read `"A"` before and
12949
+ * reads `"R"` here, every field a valid member of its union. What is
12950
+ * one-directional is the safety, which is a different statement.
12951
+ * - **Only three values in the escaped set ever shifted the segment's own
12952
+ * element framing**: the element separator, the segment terminator, and
12953
+ * a `?` immediately before the separator. **`^` and `:` moved the
12954
+ * dot-path reader instead, and releasing them is a GAIN there.**
12955
+ * `getSegmentValue(ta1, "01")` answered `"0000"` before for a control
12956
+ * number of `"0000^0001"`, truncating the reassociation key to the first
12957
+ * repetition, and answers `"0000^0001"` here; the composite read `"01-1"`
12958
+ * answered `"0000"` for `"0000:0001"`. **The measured pure cost is a
12959
+ * MID-STRING `?`, and only on the surfaces documented as raw**: `raw`,
12960
+ * `elements` and `parseTA1`'s fields read `"0000??0001"` where they read
12961
+ * `"0000?0001"`, while the dot-path read of THAT value unescapes and
12962
+ * answered `"0000?0001"` on both. Read the clause as scoped to the
12963
+ * mid-string `?`, because it is not true of `^` or `:` three sentences
12964
+ * up. **`getSegmentValue` takes an `X12Segment` and `Ta1Segment` carries
12965
+ * no `id`, so add one to read a TA1 through it.** No total is published:
12966
+ * that is what was measured, not a closed account.
12967
+ * - **`parseTA1` reads elements RAW, pre-`?`-unescape**, exactly as
12968
+ * `X12Segment.elements` has always documented. So a control number of
12969
+ * `"00000001?"` now reads back as `"00000001??"` rather than as
12970
+ * `"00000001?*260601"`. The disposition is correct where it was
12971
+ * inverted; the key still needs `unescapeRelease` applied by the reader.
12972
+ * That is a property of the read half and is not changed here.
12973
+ * - **A caller who was pre-releasing the value themselves** (the remedy
12974
+ * `KNOWN-LIMITATIONS.md` named while this was open) is now escaping
12975
+ * twice: `"00000001??"` in, `"00000001????"` out. The framing and the
12976
+ * disposition stay correct, and this one regresses on BOTH kinds of
12977
+ * surface - the dot-path read answers `"00000001??"` where it answered
12978
+ * `"00000001?"`. Drop the hand-rolled escape.
12979
+ *
12980
+ * **And an EMPTY control number is still not refused.** `escapeRelease`
12981
+ * early-returns on `""` and this module has no required-field guard, so
12982
+ * `interchangeControlNumber: ""` emits `TA1**260601*1200*A*000` with no
12983
+ * error, here and at every earlier release. Only a NON-string refuses.
12984
+ *
12985
+ * And the release is scoped to the delimiter set the caller states through
12986
+ * {@link BuildTA1Options} - see that interface for why guessing one is a
12987
+ * value corruption rather than a safe default.
12865
12988
  */
12866
12989
 
12867
12990
  /**
@@ -12876,7 +12999,18 @@ declare function build999(spec: Build999Spec): X12Interchange;
12876
12999
  * - `ackCode === "A"` paired with `noteCode !== "000"` →
12877
13000
  * {@link "./errors.js".ACK_BUILD_ERROR_CODES.X12_TA1_ACCEPT_WITH_NOTE}.
12878
13001
  * Accept must mean accept. Use `E` (accept with errors) when the
12879
- * inbound had structural defects you elected to ignore.
13002
+ * inbound had structural defects you elected to ignore. This one runs
13003
+ * FIRST and its precedence is unchanged.
13004
+ * - Any of the five element values that is not a `string` →
13005
+ * {@link "./errors.js".ACK_BUILD_ERROR_CODES.X12_ACK_INVALID_SPEC}. This
13006
+ * is not a bonus guard: releasing a value means routing it through
13007
+ * {@link "../../builder/caller-string.js".makeCallerEscaper}, and the
13008
+ * bare `escapeRelease` underneath it returns its empty accumulator for a
13009
+ * `number`, so escaping without the type check would have replaced the
13010
+ * shifted-element defect with a silently VANISHED TA1-01. **A number or
13011
+ * an `undefined` control number used to emit as `TA1*12345*…` (the
13012
+ * number surviving onto `elements`, in a `readonly string[]`) or
13013
+ * `TA1**250101*…`; both now refuse.**
12880
13014
  *
12881
13015
  * @param spec - The TA1 fields. `interchangeControlNumber` echoes the
12882
13016
  * inbound ISA-13; `interchangeDate` / `interchangeTime` echo
@@ -12914,13 +13048,28 @@ declare function build999(spec: Build999Spec): X12Interchange;
12914
13048
  */
12915
13049
  declare function buildTA1(spec: BuildTA1Spec, options?: BuildTA1Options): Ta1Segment;
12916
13050
  /**
12917
- * Options accepted by {@link buildTA1}. Both fields are optional - pass
12918
- * none for the cosyte default envelope (`*` element separator). Override
12919
- * only when the TA1 is being embedded in an outer envelope whose declared
12920
- * delimiters differ from the cosyte default.
13051
+ * Options accepted by {@link buildTA1}: the delimiter set the returned
13052
+ * segment will be read against. Every field is optional and defaults to the
13053
+ * cosyte parser archetype (`*` element, `^` repetition, `:` component, `~`
13054
+ * segment), which is the same four `build999` takes on
13055
+ * {@link "./types.js".Build999EnvelopeSpec}.
13056
+ *
13057
+ * **The three non-element fields exist for ESCAPING and nothing else.**
13058
+ * `buildTA1` still emits no segment terminator, no repetition and no
13059
+ * composite. It has to know them because a caller value carrying one of
13060
+ * them has to be released, and because escaping a byte that is NOT a
13061
+ * delimiter where the segment lands corrupts the value: `unescapeRelease`
13062
+ * preserves `?X` verbatim for any `X` outside the declared set, so a value
13063
+ * released against a guessed delimiter comes back carrying a stray `?`.
13064
+ * **If you embed a TA1 in an envelope whose delimiters are not the
13065
+ * archetype, state them here** - the defaults are an assumption this
13066
+ * function cannot verify, exactly as they were before it escaped anything.
12921
13067
  */
12922
13068
  interface BuildTA1Options {
12923
13069
  readonly elementSeparator?: string;
13070
+ readonly repetitionSeparator?: string;
13071
+ readonly componentSeparator?: string;
13072
+ readonly segmentTerminator?: string;
12924
13073
  }
12925
13074
 
12926
13075
  /**
package/dist/index.d.ts CHANGED
@@ -2483,9 +2483,10 @@ declare function unescapeRelease(input: string, delimiters: Delimiters, emit: (w
2483
2483
  * the untyped-refusal defect this package has fixed elsewhere. This is a pure
2484
2484
  * text utility with no spec, no element and no caller context to name, so
2485
2485
  * `TypeError` is the accurate answer for a wrong-typed argument. **Nothing
2486
- * inside this library can reach it**: all nine builders route every element
2486
+ * inside this library can reach it**: every builder routes its elements
2487
2487
  * through `src/builder/caller-string.ts`, which refuses first with the calling
2488
- * builder's own typed, code-tagged error. This throw is the backstop for a
2488
+ * builder's own typed, code-tagged error. (No count: it is asserted by
2489
+ * `test/builder-string-type.test.ts` and was stale here.) This throw is the backstop for a
2489
2490
  * consumer calling the export directly, where the alternative was silent data
2490
2491
  * loss.
2491
2492
  *
@@ -5720,22 +5721,23 @@ declare function get837Claims(delimiters: Delimiters, tx: X12TransactionSet, opt
5720
5721
 
5721
5722
  /**
5722
5723
  * Interchange + group + transaction identity for the built 837. The builder
5723
- * fixes GS-01 to `"HC"` and the ST-03 / GS-08 version to the variant's TR3
5724
- * (`005010X222A2` / `X223A3` / `X224A2`) so the caller never hand-codes them.
5725
- *
5726
- * **🩺 Known limitation, disclosed rather than changed: those three are
5727
- * published errata guides, but they are neither the identifiers HIPAA
5728
- * adopts at 45 CFR 162.1102 nor the ones payer companion guides commonly
5729
- * require in ST-03 / GS-08** (CMS and several state Medicaid guides state
5730
- * `005010X222A1` for Professional, `005010X223A2` for Institutional and
5731
- * `005010X224A2` for Dental). **A partner that requires one of those will
5732
- * reject a Professional or Institutional 837 this builder emits, and there
5733
- * is currently no way for a caller to override the value.** Nothing here
5734
- * was re-stamped on that evidence: which published guide identifier a
5735
- * trading partner accepts is a partner fact, not a spec fact, and silently
5736
- * changing bytes this library already emitted would break the partners it
5737
- * works with today. `KNOWN-LIMITATIONS.md` carries this as an open
5738
- * residual. The READ side is unaffected - `get837Claims` recognises all of
5724
+ * fixes GS-01 to `"HC"`, and defaults the ST-03 / GS-08 reference to the
5725
+ * variant's TR3 (`005010X222A2` / `X223A3` / `X224A2`) so the caller never
5726
+ * has to hand-code it.
5727
+ *
5728
+ * **🩺 That default is not what every trading partner accepts, so
5729
+ * {@link Build837EnvelopeSpec.implementationConventionReference} overrides
5730
+ * it.** The three defaults are published errata guides, but they are
5731
+ * neither the identifiers HIPAA adopts at 45 CFR 162.1102 nor the ones
5732
+ * payer companion guides commonly require in ST-03 / GS-08 (CMS and several
5733
+ * state Medicaid guides state `005010X222A1` for Professional and
5734
+ * `005010X223A2` for Institutional). **A partner that requires one of those
5735
+ * will reject a Professional or Institutional 837 built on the default**,
5736
+ * and the override is how you send what your partner asked for. The default
5737
+ * itself was deliberately NOT re-stamped: which published guide identifier
5738
+ * a partner accepts is a partner fact rather than a spec fact, and changing
5739
+ * bytes this library already emitted would break the partners it works with
5740
+ * today. The READ side is unaffected - `get837Claims` recognises all of
5739
5741
  * these references.
5740
5742
  *
5741
5743
  * @example
@@ -5764,6 +5766,44 @@ interface Build837EnvelopeSpec {
5764
5766
  readonly groupControlNumber: string;
5765
5767
  /** ST-02 / SE-02 - transaction set control number. */
5766
5768
  readonly transactionSetControlNumber: string;
5769
+ /**
5770
+ * 🩺 ST-03 **and** GS-08 - the implementation convention reference this
5771
+ * 837 declares. Default: the variant's TR3 (`005010X222A2` Professional,
5772
+ * `005010X223A3` Institutional, `005010X224A2` Dental).
5773
+ *
5774
+ * **Set it to whatever your trading partner's companion guide requires**,
5775
+ * for example `005010X222A1` on a professional claim to a payer that asks
5776
+ * for it. Which published identifier a partner accepts is a partner fact,
5777
+ * so this library will not choose for you: it defaults to a real published
5778
+ * guide and gets out of the way. **One value is written to both elements**,
5779
+ * because this builder has always written the same reference to ST-03 and
5780
+ * GS-08 and nothing grounds a caller making them differ. That is a statement
5781
+ * about the bytes this field emits, not about what each element may legally
5782
+ * hold: GS-08 is data element 480 (`AN 1/12`) and ST-03 is element 1705
5783
+ * (`AN 1/35`), and nothing here bounds the length.
5784
+ *
5785
+ * Refused, all `X12_837_BUILD_INVALID_SPEC`. An **empty** string, because a
5786
+ * trailing empty element is dropped on emit, so it would delete ST-03 and
5787
+ * GS-08 rather than send them empty. One carrying an **active delimiter or
5788
+ * the release character**, because these two elements cannot carry it even
5789
+ * escaped: the ST and GS segments are read by a splitter that is not
5790
+ * release-aware, so the declaration would silently become two elements. And
5791
+ * one **this library's own reader resolves to a different variant**
5792
+ * (`005010X223A2` handed to `build837P`): the file would declare one variant
5793
+ * and carry another's service segments, and `get837Claims` would then decode
5794
+ * none of its service lines. Those are what this field adds, on top of the
5795
+ * element-type guard every string slot already has, which refuses a
5796
+ * non-string with the same code - no total is published. **Anything else is
5797
+ * emitted as given** - the set of published errata is not provably
5798
+ * exhaustive, so an identifier this library does not carry is the caller's
5799
+ * call, not an error.
5800
+ *
5801
+ * 🩺 A guard on this element cannot make the element trustworthy. An active
5802
+ * delimiter in a DIFFERENT envelope field splits its own segment and shifts
5803
+ * every element after it, so ST-03 / GS-08 are then read out of a
5804
+ * neighbour's slot. `KNOWN-LIMITATIONS.md` carries the measurement.
5805
+ */
5806
+ readonly implementationConventionReference?: string;
5767
5807
  /** ISA-05 - interchange sender qualifier. Default `"ZZ"`. */
5768
5808
  readonly senderQualifier?: string;
5769
5809
  /** ISA-07 - interchange receiver qualifier. Default `"ZZ"`. */
@@ -6475,8 +6515,9 @@ interface Build837Spec {
6475
6515
 
6476
6516
  /**
6477
6517
  * `build837P` / `build837I` / `build837D` - pure-function builders for a
6478
- * 005010 837 Healthcare Claim (Professional `X222A2`, Institutional
6479
- * `X223A3`, Dental `X224A2`). NEVER auto-sends, NEVER opens a socket, NEVER
6518
+ * 005010 837 Healthcare Claim (Professional, Institutional, Dental; the
6519
+ * ST-03 / GS-08 guide reference defaults to `X222A2` / `X223A3` / `X224A2`
6520
+ * and the caller may state another). NEVER auto-sends, NEVER opens a socket, NEVER
6480
6521
  * touches the filesystem. The library mechanically emits the claim it is
6481
6522
  * told; a spec whose billing-provider → subscriber → (claims | patient)
6482
6523
  * tree cannot form a valid HL hierarchy is REFUSED via {@link
@@ -6505,7 +6546,9 @@ interface Build837Spec {
6505
6546
  */
6506
6547
 
6507
6548
  /**
6508
- * `build837P` - assemble a 005010X222A2 Professional 837 around the spec.
6549
+ * `build837P` - assemble a Professional 837 around the spec, declaring
6550
+ * `005010X222A2` unless `envelope.implementationConventionReference` states
6551
+ * the guide your trading partner requires.
6509
6552
  *
6510
6553
  * @example
6511
6554
  * ```ts
@@ -6537,8 +6580,10 @@ interface Build837Spec {
6537
6580
  */
6538
6581
  declare function build837P(spec: Build837Spec): X12Interchange;
6539
6582
  /**
6540
- * `build837I` - assemble a 005010X223A3 Institutional 837 around the spec.
6541
- * Service lines must be `variant: "I"` (SV2).
6583
+ * `build837I` - assemble an Institutional 837 around the spec, declaring
6584
+ * `005010X223A3` unless `envelope.implementationConventionReference` states
6585
+ * the guide your trading partner requires. Service lines must be
6586
+ * `variant: "I"` (SV2).
6542
6587
  *
6543
6588
  * @example
6544
6589
  * ```ts
@@ -6549,8 +6594,10 @@ declare function build837P(spec: Build837Spec): X12Interchange;
6549
6594
  */
6550
6595
  declare function build837I(spec: Build837Spec): X12Interchange;
6551
6596
  /**
6552
- * `build837D` - assemble a 005010X224A2 Dental 837 around the spec. Service
6553
- * lines must be `variant: "D"` (SV3); per-line tooth detail rides on TOO.
6597
+ * `build837D` - assemble a Dental 837 around the spec, declaring
6598
+ * `005010X224A2` unless `envelope.implementationConventionReference` states
6599
+ * the guide your trading partner requires. Service lines must be
6600
+ * `variant: "D"` (SV3); per-line tooth detail rides on TOO.
6554
6601
  *
6555
6602
  * @example
6556
6603
  * ```ts
@@ -12862,6 +12909,82 @@ declare function build999(spec: Build999Spec): X12Interchange;
12862
12909
  * library does NOT silently invent envelope bytes around it - the caller's
12863
12910
  * application boundary owns whether the TA1 is embedded in an outbound
12864
12911
  * interchange or sent as a standalone TA1-only interchange.
12912
+ *
12913
+ * ## 🩺 Why every element is released, and what that changed
12914
+ *
12915
+ * `raw` used to be `[...five caller values].join(elementSeparator)` with
12916
+ * nothing in between, so a caller value carrying an active delimiter took
12917
+ * a slot of its own and shifted every element after it down one. TA1-04 is
12918
+ * the disposition and TA1-05 the note, so the shift landed the read on the
12919
+ * wrong pair, and `parseTA1` narrows an out-of-enum TA1-04 to `R`:
12920
+ * **an Accept this library emitted read back as a Reject**, with the TA1-01
12921
+ * reassociation key merged into TA1-02 and `warnings: []` on every channel.
12922
+ * The inverse is the less safe one and also existed: a `noteCode` of
12923
+ * literally `"A"` (a value the type forbids and nothing checks at run time)
12924
+ * shifted onto TA1-04 and made a **Reject read back as an Accept**, which a
12925
+ * sender never resubmits against.
12926
+ *
12927
+ * The grounding is inside the package, not in a spec clause, which is the
12928
+ * same tiebreak `X12-ENVELOPE-SPLITTER-NOT-RELEASE-AWARE` recorded: one
12929
+ * function disagreed with itself. This module emitted bytes that this
12930
+ * package's own reader decoded into a different disposition than the one
12931
+ * the caller asked for, and every other builder already released the same
12932
+ * class of element through the same helper.
12933
+ *
12934
+ * **It changes bytes, and that is the cost that kept it open for a slice.**
12935
+ * A value containing none of the four delimiters or the release character
12936
+ * is emitted byte-for-byte as before, which is every conformant TA1. A
12937
+ * value containing one is now released, so its bytes differ from the ones
12938
+ * `0.0.14` and earlier put on the wire. What that costs is stated outright
12939
+ * below rather than argued away, and **without a total**: two drafts of this
12940
+ * account published a closed one and both were refuted.
12941
+ *
12942
+ * - **The consumer predicate moves in BOTH directions.** Read the property
12943
+ * rather than a direction list: `parseTA1` of a `buildTA1` output now
12944
+ * reports the disposition and note the CALLER passed, where before it
12945
+ * reported whatever element the shift left in TA1-04. So
12946
+ * `ackCode === "R"` stops firing where an Accept had been shifted onto
12947
+ * it, and starts firing where a Reject had been shifted off it -
12948
+ * `interchangeTime: "12*A"` with `ackCode: "R"` read `"A"` before and
12949
+ * reads `"R"` here, every field a valid member of its union. What is
12950
+ * one-directional is the safety, which is a different statement.
12951
+ * - **Only three values in the escaped set ever shifted the segment's own
12952
+ * element framing**: the element separator, the segment terminator, and
12953
+ * a `?` immediately before the separator. **`^` and `:` moved the
12954
+ * dot-path reader instead, and releasing them is a GAIN there.**
12955
+ * `getSegmentValue(ta1, "01")` answered `"0000"` before for a control
12956
+ * number of `"0000^0001"`, truncating the reassociation key to the first
12957
+ * repetition, and answers `"0000^0001"` here; the composite read `"01-1"`
12958
+ * answered `"0000"` for `"0000:0001"`. **The measured pure cost is a
12959
+ * MID-STRING `?`, and only on the surfaces documented as raw**: `raw`,
12960
+ * `elements` and `parseTA1`'s fields read `"0000??0001"` where they read
12961
+ * `"0000?0001"`, while the dot-path read of THAT value unescapes and
12962
+ * answered `"0000?0001"` on both. Read the clause as scoped to the
12963
+ * mid-string `?`, because it is not true of `^` or `:` three sentences
12964
+ * up. **`getSegmentValue` takes an `X12Segment` and `Ta1Segment` carries
12965
+ * no `id`, so add one to read a TA1 through it.** No total is published:
12966
+ * that is what was measured, not a closed account.
12967
+ * - **`parseTA1` reads elements RAW, pre-`?`-unescape**, exactly as
12968
+ * `X12Segment.elements` has always documented. So a control number of
12969
+ * `"00000001?"` now reads back as `"00000001??"` rather than as
12970
+ * `"00000001?*260601"`. The disposition is correct where it was
12971
+ * inverted; the key still needs `unescapeRelease` applied by the reader.
12972
+ * That is a property of the read half and is not changed here.
12973
+ * - **A caller who was pre-releasing the value themselves** (the remedy
12974
+ * `KNOWN-LIMITATIONS.md` named while this was open) is now escaping
12975
+ * twice: `"00000001??"` in, `"00000001????"` out. The framing and the
12976
+ * disposition stay correct, and this one regresses on BOTH kinds of
12977
+ * surface - the dot-path read answers `"00000001??"` where it answered
12978
+ * `"00000001?"`. Drop the hand-rolled escape.
12979
+ *
12980
+ * **And an EMPTY control number is still not refused.** `escapeRelease`
12981
+ * early-returns on `""` and this module has no required-field guard, so
12982
+ * `interchangeControlNumber: ""` emits `TA1**260601*1200*A*000` with no
12983
+ * error, here and at every earlier release. Only a NON-string refuses.
12984
+ *
12985
+ * And the release is scoped to the delimiter set the caller states through
12986
+ * {@link BuildTA1Options} - see that interface for why guessing one is a
12987
+ * value corruption rather than a safe default.
12865
12988
  */
12866
12989
 
12867
12990
  /**
@@ -12876,7 +12999,18 @@ declare function build999(spec: Build999Spec): X12Interchange;
12876
12999
  * - `ackCode === "A"` paired with `noteCode !== "000"` →
12877
13000
  * {@link "./errors.js".ACK_BUILD_ERROR_CODES.X12_TA1_ACCEPT_WITH_NOTE}.
12878
13001
  * Accept must mean accept. Use `E` (accept with errors) when the
12879
- * inbound had structural defects you elected to ignore.
13002
+ * inbound had structural defects you elected to ignore. This one runs
13003
+ * FIRST and its precedence is unchanged.
13004
+ * - Any of the five element values that is not a `string` →
13005
+ * {@link "./errors.js".ACK_BUILD_ERROR_CODES.X12_ACK_INVALID_SPEC}. This
13006
+ * is not a bonus guard: releasing a value means routing it through
13007
+ * {@link "../../builder/caller-string.js".makeCallerEscaper}, and the
13008
+ * bare `escapeRelease` underneath it returns its empty accumulator for a
13009
+ * `number`, so escaping without the type check would have replaced the
13010
+ * shifted-element defect with a silently VANISHED TA1-01. **A number or
13011
+ * an `undefined` control number used to emit as `TA1*12345*…` (the
13012
+ * number surviving onto `elements`, in a `readonly string[]`) or
13013
+ * `TA1**250101*…`; both now refuse.**
12880
13014
  *
12881
13015
  * @param spec - The TA1 fields. `interchangeControlNumber` echoes the
12882
13016
  * inbound ISA-13; `interchangeDate` / `interchangeTime` echo
@@ -12914,13 +13048,28 @@ declare function build999(spec: Build999Spec): X12Interchange;
12914
13048
  */
12915
13049
  declare function buildTA1(spec: BuildTA1Spec, options?: BuildTA1Options): Ta1Segment;
12916
13050
  /**
12917
- * Options accepted by {@link buildTA1}. Both fields are optional - pass
12918
- * none for the cosyte default envelope (`*` element separator). Override
12919
- * only when the TA1 is being embedded in an outer envelope whose declared
12920
- * delimiters differ from the cosyte default.
13051
+ * Options accepted by {@link buildTA1}: the delimiter set the returned
13052
+ * segment will be read against. Every field is optional and defaults to the
13053
+ * cosyte parser archetype (`*` element, `^` repetition, `:` component, `~`
13054
+ * segment), which is the same four `build999` takes on
13055
+ * {@link "./types.js".Build999EnvelopeSpec}.
13056
+ *
13057
+ * **The three non-element fields exist for ESCAPING and nothing else.**
13058
+ * `buildTA1` still emits no segment terminator, no repetition and no
13059
+ * composite. It has to know them because a caller value carrying one of
13060
+ * them has to be released, and because escaping a byte that is NOT a
13061
+ * delimiter where the segment lands corrupts the value: `unescapeRelease`
13062
+ * preserves `?X` verbatim for any `X` outside the declared set, so a value
13063
+ * released against a guessed delimiter comes back carrying a stray `?`.
13064
+ * **If you embed a TA1 in an envelope whose delimiters are not the
13065
+ * archetype, state them here** - the defaults are an assumption this
13066
+ * function cannot verify, exactly as they were before it escaped anything.
12921
13067
  */
12922
13068
  interface BuildTA1Options {
12923
13069
  readonly elementSeparator?: string;
13070
+ readonly repetitionSeparator?: string;
13071
+ readonly componentSeparator?: string;
13072
+ readonly segmentTerminator?: string;
12924
13073
  }
12925
13074
 
12926
13075
  /**