@cosyte/x12 0.0.18 → 0.1.0
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 +100 -4
- package/KNOWN-LIMITATIONS.md +435 -36
- package/README.md +268 -24
- package/dist/index.cjs +5864 -1152
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7975 -1457
- package/dist/index.d.ts +7975 -1457
- package/dist/index.mjs +5777 -1153
- package/dist/index.mjs.map +1 -1
- package/package.json +58 -27
package/KNOWN-LIMITATIONS.md
CHANGED
|
@@ -136,6 +136,34 @@ model.
|
|
|
136
136
|
refused before this change is refused differently by it.**
|
|
137
137
|
- **No census of other builders' required elements is published here.** This change measured TA1.
|
|
138
138
|
|
|
139
|
+
- **🩺 Every typed reader checks the implementation guide a transaction set declares against the
|
|
140
|
+
guides that reader implements, and WARNS rather than refuses where they differ.**
|
|
141
|
+
`X12_GUIDE_NOT_IMPLEMENTED` is raised where the declared guide is outside the reader's set and
|
|
142
|
+
`X12_GUIDE_NOT_DECLARED` where nothing is declared, both anchored at the ST. The reading is
|
|
143
|
+
decoded and returned either way, against the element positions of the guide the reader
|
|
144
|
+
implements, so on a warned document a value can sit at a position the declared guide defines
|
|
145
|
+
differently. What the check keys on, exactly:
|
|
146
|
+
- **The declaration is `ST-03` decoded, then `GS-08` decoded.** `ST-03` is read post-`?`-unescape,
|
|
147
|
+
exactly as `implementationConventionReference` is published. Only where `ST-03` is absent or
|
|
148
|
+
decodes to `""` is GS-08 of the enclosing functional group read, decoded the same way; a parsed
|
|
149
|
+
transaction set carries its group's GS header on `tx.gs` for this, and one assembled by hand
|
|
150
|
+
without it is read as GS-08 absent. Nothing is trimmed, case-folded or prefix-matched, so a
|
|
151
|
+
whitespace-only or lower-cased declaration is reported as not implemented.
|
|
152
|
+
- **🛑 `ST-03` and `GS-08` are NOT reconciled.** Where `ST-03` is non-empty it alone decides and
|
|
153
|
+
GS-08 is never read, so a document whose two declarations disagree is judged on `ST-03` and
|
|
154
|
+
nothing reports the disagreement.
|
|
155
|
+
- **The implemented set is `X12_TR3_CONFORMANCE`**, each of the reader's rows contributing its
|
|
156
|
+
`tr3` and every `cfrAdopted` entry. **The 837 reader also recognises every identifier its
|
|
157
|
+
variant table resolves**, which includes the companion-guide identifiers production claims carry,
|
|
158
|
+
so a conformant claim declaring one is not accused. A 278 declaring `005010X216`, the 278
|
|
159
|
+
notification guide, is warned on both 278 readers.
|
|
160
|
+
- **What the check decides is a warning, plus one label.** A 277 whose declared guide is outside
|
|
161
|
+
`get277Status`'s set, or absent, reads `transactionType: "unrecognized-guide"`. Everything else
|
|
162
|
+
that keys on `ST-03` - the 837 variant, the choice between `claim-status` and
|
|
163
|
+
`claim-acknowledgment`, and `get277CADisposition`'s admission - still keys on the raw text and
|
|
164
|
+
did not move, so the check and those decisions can read the same `ST-03` differently where a
|
|
165
|
+
release escape is involved (see the next entry).
|
|
166
|
+
|
|
139
167
|
- **🩺 `implementationConventionReference` is POST-`?`-unescape as of this release, in every typed
|
|
140
168
|
reader that publishes it, and that is a behaviour change on documents whose `ST-03` carries a
|
|
141
169
|
release escape.** `tx.st.elements` is the ST segment as framed:
|
|
@@ -149,8 +177,8 @@ model.
|
|
|
149
177
|
publishes `A*B`, `A?:B` publishes `A:B`, `A?~B` publishes `A~B`, `A?^B` publishes `A^B`. Every one
|
|
150
178
|
of those published the framed bytes before.
|
|
151
179
|
- **🛑 What decides an outcome did NOT move, deliberately.** The 837 variant lookup, the 277 /
|
|
152
|
-
277CA `transactionType`
|
|
153
|
-
the RAW element text, so no document changes variant, discriminator or admission because of this
|
|
180
|
+
277CA `transactionType` choice between its two claim labels and `get277CADisposition`'s
|
|
181
|
+
admission gate all still key on the RAW element text, so no document changes variant, discriminator or admission because of this
|
|
154
182
|
entry. That matters because the two can differ: with `componentSeparator: "X"` - a letter is an
|
|
155
183
|
admissible delimiter - an `ST-03` framed as `005010?X222A1` decodes to `005010X222A1`, an
|
|
156
184
|
identifier the variant table holds. Keying on the decoded text would make the declaration beat
|
|
@@ -1259,9 +1287,11 @@ Code"`, `SVC05 / 380 / "Units of Service Paid Count"`, `SVC06 / C003`,
|
|
|
1259
1287
|
the long-tail codes most workflows branch on. An inbound code **outside** a snapshot still parses:
|
|
1260
1288
|
the verbatim code is preserved on the model and an `X12_UNKNOWN_*` warning is raised. Only the
|
|
1261
1289
|
human-readable **description** is absent (`undefined`). A stale or partial snapshot therefore yields
|
|
1262
|
-
a missing description, **never a wrong code**.
|
|
1263
|
-
|
|
1264
|
-
|
|
1290
|
+
a missing description, **never a wrong code**. Every snapshot states which it is: `meta.completeness`
|
|
1291
|
+
is `"cited-subset"` on all seven today, so a lookup miss means this package does not carry the code
|
|
1292
|
+
and never that the publisher did not issue it. Run `pnpm refresh:code-lists` to audit snapshot
|
|
1293
|
+
freshness; regenerating the full lists (`--fetch`) is a release step gated per list on that list's
|
|
1294
|
+
own recorded redistribution terms (see below), not a runtime fetch.
|
|
1265
1295
|
|
|
1266
1296
|
- **`serialize(parse(s)) === s` is NOT guaranteed.** `serializeX12` rebuilds the interchange from the
|
|
1267
1297
|
model, so every segment the parser recorded comes back verbatim (element padding, composites, and
|
|
@@ -1328,14 +1358,15 @@ Code"`, `SVC05 / 380 / "Units of Service Paid Count"`, `SVC06 / C003`,
|
|
|
1328
1358
|
context and anchor), `ta1Segments`, `trailingBytes` and the warning multiset are unchanged by the
|
|
1329
1359
|
round trip, and every emit is a fixed point.
|
|
1330
1360
|
|
|
1331
|
-
What is **measured** across
|
|
1361
|
+
What is **measured** across every committed fixture: each emit is a fixed point (serializing it
|
|
1332
1362
|
again is a byte-level no-op) and re-parses to an identical model with an identical warning stream;
|
|
1333
|
-
the
|
|
1363
|
+
the fixtures with no line breaks return byte-identical; and the rest differ from their source
|
|
1334
1364
|
by **line breaks and nothing else**, with no element value lost, altered, reordered, or re-escaped.
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1365
|
+
No corpus size is quoted: it moves with every fixture added, and `test/serialize.test.ts`
|
|
1366
|
+
re-derives the sweep from the tree on every run. Two caveats on that corpus, both of which limit
|
|
1367
|
+
how far the sweep can be pushed: it contains **no instance of cases 2 to 6** (zero fixtures produce
|
|
1368
|
+
an `orphanSegments` entry, which is why the orphan sweep above is constructed rather than drawn
|
|
1369
|
+
from it), and **all but one of the byte-identical fixtures are `golden/*.edi`**, which
|
|
1339
1370
|
are serializer output by construction, leaving `envelope/no-trailing-crlf.edi` as the only
|
|
1340
1371
|
independent witness. Preserving the original framing byte-for-byte would need the model to carry
|
|
1341
1372
|
per-segment framing and TA1 position it does not have today; that is a tracked model change, not a
|
|
@@ -1578,12 +1609,14 @@ N-char spec limit` refusal, one per emitting module, where the branch fires **be
|
|
|
1578
1609
|
|
|
1579
1610
|
- **A forged non-array in a builder spec refuses; in a few places it throws an untyped `TypeError`.**
|
|
1580
1611
|
The types say `readonly T[]`, but a JavaScript or JSON caller can hand a builder something else. As
|
|
1581
|
-
of `0.0.6` every indexed loop in every builder takes its bound from a checked array
|
|
1582
|
-
|
|
1612
|
+
of `0.0.6` every indexed loop in every builder takes its bound from a checked array, so an object
|
|
1613
|
+
like `{ length: "9".repeat(120000) }` draws that builder's own typed
|
|
1583
1614
|
refusal - previously the length coerced to `Infinity` and the builder **looped forever instead of
|
|
1584
|
-
refusing**.
|
|
1585
|
-
|
|
1586
|
-
`
|
|
1615
|
+
refusing**. No loop or probe count is quoted here: both move with every builder added, and
|
|
1616
|
+
`test/builder-array-bounds.test.ts` re-derives them from the source on every run. Measured over the
|
|
1617
|
+
probes that suite shipped at the `0.0.6` base: most **hung** with no refusal and the rest threw an
|
|
1618
|
+
untyped `TypeError`. Each of those probes now refuses with a typed, coded error, except the
|
|
1619
|
+
`for…of` reads below, which still throw the untyped `TypeError`.
|
|
1587
1620
|
|
|
1588
1621
|
**`null` is treated as absent, not forged**, exactly as the `?? []` this replaced did, so an
|
|
1589
1622
|
optional list you send as `null` still builds. On a required list `null` draws that builder's own
|
|
@@ -1593,11 +1626,24 @@ N-char spec limit` refusal, one per emitting module, where the branch fires **be
|
|
|
1593
1626
|
|
|
1594
1627
|
Not covered, and disclosed rather than fixed: the places a builder reads a caller array with
|
|
1595
1628
|
`for…of` - `buildInterchange`'s `spec.groups`, `build999`'s `functionalGroup.transactionResponses`,
|
|
1596
|
-
and
|
|
1629
|
+
and the optional leaf arrays such as `claim.dates` or `member.references`. Those throw
|
|
1597
1630
|
`TypeError: … is not iterable` immediately. They terminate, so they are not the hang, but they carry
|
|
1598
1631
|
**no `code`**, so `err.code` is `undefined` and you cannot branch on it. Validate your spec shape at
|
|
1599
1632
|
your own boundary if it comes from JSON.
|
|
1600
1633
|
|
|
1634
|
+
**`build270` is the exception, and it is deliberately stricter than its siblings.** EVERY list slot
|
|
1635
|
+
on `Build270Spec` - the spine (`informationSources`, `receivers`, `subscribers`, `dependents`,
|
|
1636
|
+
`inquiries`, `serviceTypeCodes`) and the leaves (`traces`, `references`, `dates`, `address.lines`,
|
|
1637
|
+
`diagnosisCodePointers`, `procedure.modifiers`) alike - is read through the same checked-array
|
|
1638
|
+
chokepoint, so a forged array-like anywhere in a 270 spec draws a typed, code-tagged
|
|
1639
|
+
`Eligibility270BuildError` rather than an untyped `TypeError`. **The same slots are checked for
|
|
1640
|
+
HOLES at the same point**, because a real array with `undefined` or `null` sitting in a slot is a
|
|
1641
|
+
list and clears the chokepoint: that is the shape a JSON payload with a dropped record carries, and
|
|
1642
|
+
unguarded it reached an emitter and threw the untyped `TypeError` this whole section is about. A
|
|
1643
|
+
hole refuses wherever it stands, naming the slot and nothing out of the inquiry. A name loop sent
|
|
1644
|
+
as `null` is refused the same way, at every level. The other builders are unchanged: on those, a
|
|
1645
|
+
hole in a list still reaches whatever dereferences it.
|
|
1646
|
+
|
|
1601
1647
|
**One qualification worth stating precisely: on the acknowledgment path the value is not always
|
|
1602
1648
|
strictly your own.** TR3 005010X231A1 requires AK2-02 to be a verbatim copy of the acknowledged
|
|
1603
1649
|
transaction set's ST-02, and `buildTA1` exists to echo an inbound ISA-13, so a _document's_ control
|
|
@@ -1644,39 +1690,392 @@ N-char spec limit` refusal, one per emitting module, where the branch fires **be
|
|
|
1644
1690
|
mismatch and preserve the inbound values verbatim. The library will not "fix" a payer artifact for
|
|
1645
1691
|
you. Gate your own posting/adjudication on the warning.
|
|
1646
1692
|
|
|
1647
|
-
##
|
|
1648
|
-
|
|
1649
|
-
- **
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1693
|
+
## Trading-partner profiles: what a conformance classification is, and is not
|
|
1694
|
+
|
|
1695
|
+
- **A profile never changes what this library emits.** A profile describes what a trading partner
|
|
1696
|
+
SENDS. It attaches attribution to a parse and partitions that parse's warnings into expected and
|
|
1697
|
+
unexpected, and that is the whole of its behaviour. It cannot loosen, tighten or otherwise touch
|
|
1698
|
+
the emit side: `serializeX12`, `buildInterchange` and every `build*` domain builder produce
|
|
1699
|
+
byte-identical output with any profile active and with none, and refuse the same specs with the
|
|
1700
|
+
same error type, code and message. There is no opt-in flag that would change this, and
|
|
1701
|
+
`test/profiles-emit-independence.test.ts` fails the build if the property is ever broken. The
|
|
1702
|
+
reason it is a locked invariant rather than a convention: a profile that widened the emit would
|
|
1703
|
+
put a non-conformant document on the wire, and 45 CFR 162.915 forbids the trading partner from
|
|
1704
|
+
having asked for that in the first place.
|
|
1705
|
+
|
|
1706
|
+
- **Each quirk's conformance classification is a RECORDED HUMAN JUDGEMENT, not a check this
|
|
1707
|
+
library performed.** `describe()` states, per quirk, whether the deviation is one a trading partner
|
|
1708
|
+
may lawfully require. Read that as documentation someone wrote down, and confirm it against your
|
|
1709
|
+
own copy of the relevant implementation guide before you rely on it. In particular, **a
|
|
1710
|
+
classification that turns on an element being marked "not used" in an adopted TR3 rests on someone
|
|
1711
|
+
having read that TR3.** This package bundles none: 45 CFR 162.920(a) states a fee is charged for
|
|
1712
|
+
the implementation specifications, so "is this element marked not used?" is not a question the
|
|
1713
|
+
library can answer at run time, and it does not pretend to. Nothing in the classification is
|
|
1714
|
+
derived from your document, from the quirk's `effect`, or from any code list shipped here.
|
|
1715
|
+
|
|
1716
|
+
- **The axis is 45 CFR 162.915, and it has three states, not two.** `permitted` and `not-permitted`
|
|
1717
|
+
are measured against that rule, which forbids a covered entity from entering a trading partner
|
|
1718
|
+
agreement that would change the definition, data condition or use of a data element or segment in
|
|
1719
|
+
a standard, add data elements or segments to the maximum defined data set, use any code or data
|
|
1720
|
+
element marked "not used" in (or absent from) the standard's implementation specification, or
|
|
1721
|
+
change the meaning or intent of that implementation specification. The third state,
|
|
1722
|
+
`undetermined`, means **no judgement was recorded**, and it is the fail-safe default: a quirk that
|
|
1723
|
+
says nothing about conformance renders as `undetermined`, never as `permitted`. Read
|
|
1724
|
+
`undetermined` as "this package makes no claim", which is not the same as "harmless". Two of the
|
|
1725
|
+
three quirks shipped by the built-in profiles are `undetermined` today for exactly the fee reason
|
|
1726
|
+
above.
|
|
1727
|
+
|
|
1728
|
+
- **A `requires` quirk is a record of what a partner MANDATES, never a claim that the standard
|
|
1729
|
+
supports the mandate.** Those are two different statements and the buckets do not conflate them:
|
|
1730
|
+
membership of `requires` confers nothing on the conformance axis, and a partner mandating an
|
|
1731
|
+
element the adopted guide marks "not used" classifies as a deviation from the standard. If you
|
|
1732
|
+
need to know whether your partner may lawfully require something, read `conformance`, not the
|
|
1733
|
+
effect bucket.
|
|
1734
|
+
|
|
1735
|
+
## What the differential corpus proves, and what it does not
|
|
1736
|
+
|
|
1737
|
+
- **Every synthetic document this repository ships is read by this library and, where an independent
|
|
1738
|
+
reader maps its transaction, by that reader too, and the two readings are compared element
|
|
1739
|
+
position by element position.** Two independent, open-source X12 readers serve as oracles, each
|
|
1740
|
+
pinned to one exact version and used only as a development tool: neither is ever a dependency of
|
|
1741
|
+
this package, whose published runtime dependency set is empty. The first is pyx12, a BSD-licensed
|
|
1742
|
+
HIPAA X12 parser and validator. The second is LinuxForHealth x12, an Apache-2.0-licensed X12
|
|
1743
|
+
reader with a transaction model per implementation guide, pinned together with every package it
|
|
1744
|
+
runs on and the Python version it runs under, because its own metadata leaves the Pydantic release
|
|
1745
|
+
it needs free. A transaction is compared against the first oracle that maps it and against no
|
|
1746
|
+
other. `pnpm run differential` runs the comparison and writes `test/differential/report.json`,
|
|
1747
|
+
which carries each oracle's name, version and licence as the installed reader declares them (for
|
|
1748
|
+
the second, also the Python version and every companion package version it ran with), the commit
|
|
1749
|
+
this library was read from, which oracle each transaction was compared against with the
|
|
1750
|
+
implementation guide and the map or model that oracle bound it to, the documents that went through
|
|
1751
|
+
both readers, the number of element positions compared, every document the run looked at and did
|
|
1752
|
+
not compare with the reason, and every disagreement found, with both readings left exactly as each
|
|
1753
|
+
reader returned them. `pnpm run differential:check` runs the same comparison and succeeds only when
|
|
1754
|
+
it reproduces the committed report. Which comparison a document belongs to is decided by the
|
|
1755
|
+
document's own GS-08 and ST-01, never by where it is filed, so the awkward documents are in the
|
|
1756
|
+
corpus rather than beside it.
|
|
1757
|
+
- **Which reader compares what.** pyx12 compares the 277 claim acknowledgment (005010X214), the 820,
|
|
1758
|
+
the 834, the 835, the professional claim, the institutional claim and the 999. LinuxForHealth x12
|
|
1759
|
+
compares the 270, the 271, the 276 and the 277 claim status response (005010X212), for which pyx12
|
|
1760
|
+
publishes no 005010 implementation guide map. LinuxForHealth x12 also models the 834, the 835 and
|
|
1761
|
+
both claims, and those are still compared against pyx12 alone: no transaction here is read by both
|
|
1762
|
+
oracles, so no row carries two readers' agreement.
|
|
1763
|
+
- **🩺 The second oracle reads a document only through its transaction model for the guide the
|
|
1764
|
+
document declares, and that model refuses much of this corpus, so its comparisons are narrower than
|
|
1765
|
+
the documents filed under them.** A document the model refuses is recorded in the report as
|
|
1766
|
+
unevaluated, with the oracle and the kind of refusal, and never counted as agreement. Among the
|
|
1767
|
+
documents here that it refuses are the ones that deliberately break the hierarchy or a row, 271
|
|
1768
|
+
documents whose AAA rejection reasons fall outside the codes it enumerates for that loop, the 270
|
|
1769
|
+
and 271 documents carrying a dependent level, and the 276 documents whose subscriber carries a
|
|
1770
|
+
dependent level beside a claim of its own, as the canonical 276 fixture does. A model can also
|
|
1771
|
+
accept a document and set one of its segments aside without raising, so a document is compared only
|
|
1772
|
+
when the model kept every segment of every transaction set, ST through SE, that the oracle framed
|
|
1773
|
+
for it; one whose model kept fewer is recorded as unevaluated with its own refusal kind, and none of
|
|
1774
|
+
its positions is counted as agreement. 🩺 The two readers place the 276 subscriber's demographics
|
|
1775
|
+
segment (DMG) differently: that model reads it ahead of the subscriber's name and this library
|
|
1776
|
+
after it. A document carrying one where this library puts it loses it to that model, which then
|
|
1777
|
+
refuses the document; and this library's 276 reader keeps a DMG only after the name already read at
|
|
1778
|
+
its level, so one sent ahead of the name is not on the decoded inquiry and no warning says so. Which
|
|
1779
|
+
position the implementation guide specifies is not settled here, and nothing about either reader
|
|
1780
|
+
moved to produce this. So the one 276 compared against it carries no subscriber DMG. Agreement on the
|
|
1781
|
+
270, the 271, the 276 and the 277 claim status response is agreement over the documents that model
|
|
1782
|
+
accepted whole, which the report lists by name, and nothing wider: in particular no document
|
|
1783
|
+
compared against it carries a dependent level, and no 276 compared against it carries a DMG, so that
|
|
1784
|
+
comparison says nothing about either.
|
|
1785
|
+
- **🩺 This library and pyx12 disagree about the release character, and the report records the
|
|
1786
|
+
disagreement rather than settling it.** One synthetic document escapes the element separator with
|
|
1787
|
+
`?` inside a transaction set body. This library reads `?` as a release character there, as it has
|
|
1788
|
+
on every released version, so `REF*EA*ID?*WITH?*STAR` is two elements whose second value is
|
|
1789
|
+
`ID*WITH*STAR`; pyx12 reads no release character, so the same segment is four elements whose second
|
|
1790
|
+
value is `ID?`. 005010 transmits no release character at all and nothing in it picks between the
|
|
1791
|
+
two readings, which is the same ambiguity the envelope-splitter entry above is about, and it is the
|
|
1792
|
+
one input class in this corpus on which two conforming readers can genuinely differ. **The
|
|
1793
|
+
disagreement is published, not resolved:** the report holds both readings verbatim for that
|
|
1794
|
+
position, nothing about how this library reads the release character moved to produce it, and
|
|
1795
|
+
`pnpm run differential` exits non-zero for as long as it stands. If you exchange documents that
|
|
1796
|
+
escape a delimiter in a body element, do not assume your counterparty's parser frames that segment
|
|
1797
|
+
the way this one does.
|
|
1798
|
+
- **The rows of this library's read scope that neither oracle maps are compared against nothing, and
|
|
1799
|
+
the report names every one with the reason.** Neither reader publishes a 005010 implementation
|
|
1800
|
+
guide map or model for the 278 in either direction or for the dental claim, neither has one for the
|
|
1801
|
+
275 (006020X314) or the 277 request for additional information (006020X313), and neither can bind
|
|
1802
|
+
the TA1 interchange acknowledgment, which sits in the envelope rather than in a functional group
|
|
1803
|
+
and carries no implementation guide identifier. Read that as a statement about the maps and models
|
|
1804
|
+
those readers publish and not about what they can frame: what is missing is the implementation
|
|
1805
|
+
guide, not the ability to read bytes. Either way this library's reading of those transactions is
|
|
1806
|
+
compared against nothing here, and silence about them is silence, never agreement.
|
|
1807
|
+
- **For two of the compared transactions the two implementations target different published errata of
|
|
1808
|
+
the same implementation guide, and the report records both identifiers rather than implying one.**
|
|
1809
|
+
pyx12 maps an earlier errata of the professional claim and of the institutional claim than this
|
|
1810
|
+
library implements, so agreement there is agreement between two revisions of one guide.
|
|
1811
|
+
- **Agreement with either reader is not conformance to a Technical Report Type 3, and it is not a
|
|
1812
|
+
compliance statement.** Two parsers can agree and both be wrong about the same clause; neither
|
|
1813
|
+
reader is the standard, and each transaction here is compared against one of them, never both. No
|
|
1814
|
+
report produced here says anything about HIPAA compliance, which is a property of a deployment and
|
|
1815
|
+
never of a library. Conformance still rests on the three-tier synthetic corpus (spec-clean,
|
|
1816
|
+
vendor-quirk, round-trip goldens), property and round-trip tests, and a nightly amplified byte-flip
|
|
1817
|
+
fuzz job. Do not assume byte-for-byte agreement with any specific vendor parser.
|
|
1818
|
+
- **The corpus is this repository's own synthetic fixtures and nothing else.** No CMS Medicare 835
|
|
1819
|
+
public sample material is in it: the redistribution-terms review of that material is not cleared,
|
|
1820
|
+
and it is not used here until it is. What that bounds is the evidence, not the claim: two readers
|
|
1821
|
+
agreeing over synthetic documents have agreed over synthetic documents.
|
|
1655
1822
|
|
|
1656
1823
|
## Scope (non-goals for v1)
|
|
1657
1824
|
|
|
1658
|
-
- **Healthcare HIPAA 005010
|
|
1659
|
-
|
|
1660
|
-
|
|
1825
|
+
- **Healthcare HIPAA 005010, and two 006020 guides: the claims attachments pair.** Beside the
|
|
1826
|
+
005010 transaction sets, the package reads and builds the 277 Health Care Claim Request for
|
|
1827
|
+
Additional Information (`006020X313`) and the 275 Additional Information to Support a Health Care
|
|
1828
|
+
Claim or Encounter (`006020X314`), which 45 CFR 162.920(a)(20) and (a)(19) name and 45 CFR
|
|
1829
|
+
162.2002 adopts for the period on and after May 26, 2028. No other 006020 guide is read or built:
|
|
1830
|
+
the services review pair the same rule proposed and did not adopt, the 278 `006020X315` and the
|
|
1831
|
+
275 Additional Information to Support a Health Care Services Review `006020X316`, is out of
|
|
1832
|
+
scope, and a 275 declaring `006020X316` is read as a guide the 275 reader does not implement.
|
|
1833
|
+
Non-healthcare transaction sets
|
|
1834
|
+
(850/856/810/204, etc.), the EDIFACT syntax family, and pre-005010 versions are out of v1 scope.
|
|
1835
|
+
Pre-005010 input is tolerated and flagged (`X12_PRE_005010`), not decoded to those older field
|
|
1836
|
+
maps. What the attachments pair leaves open, stated here beside it:
|
|
1837
|
+
- **The base X12 006020 transaction sets are typed; no implementation-guide usage is asserted.**
|
|
1838
|
+
Both guides are sold and no source this package carries states which segments, qualifiers or
|
|
1839
|
+
codes they make required, situational or repeatable. So the readers carry every code and
|
|
1840
|
+
qualifier verbatim and decide nothing about whether it is valid for the guide, and the builders
|
|
1841
|
+
write every BHT code, HL level and child code, entity, reference and date qualifier exactly as
|
|
1842
|
+
given and supply none. `build277RequestForAdditionalInformation` refuses only the absences the
|
|
1843
|
+
base 006020 277 makes mandatory (no level, no claim-level request, a request with no TRN, an
|
|
1844
|
+
empty C043-01 or C043-02, a service line with no SVC); `build275` refuses only what would make a
|
|
1845
|
+
BDS-02 untrue or a BDS empty (no attachment, empty data, a filter code that is not three
|
|
1846
|
+
characters, a character above U+00FF). A document conformant to either guide can carry a segment
|
|
1847
|
+
or qualifier these models leave untyped: the 277's SBR, PAT, DMG, heading name loop, PWK loops
|
|
1848
|
+
and TOO, the 275's DTM, IN1, DMG, PRV, PER, NX1 and each line's NM1, HI, SVC, DTP, CAT, PID and
|
|
1849
|
+
OOI. They stay verbatim on the transaction set, and neither builder writes them: `build275`
|
|
1850
|
+
writes each BDS directly after its line's LX, TRN, STC and REF, with no DTP, CAT or OOI before
|
|
1851
|
+
it, so a trading partner whose guide places the BDS inside those loops needs them added by hand
|
|
1852
|
+
through `buildInterchange`.
|
|
1853
|
+
- **The 277 request reader validates no hierarchy.** Each HL is carried with HL-01, HL-02, HL-03
|
|
1854
|
+
and HL-04 as sent; no parent pointer is checked and no level code is expected, because no
|
|
1855
|
+
carried source states the guide's hierarchy. A claim-level segment sent before the first HL
|
|
1856
|
+
reaches no level and stays on the transaction set.
|
|
1857
|
+
- **ISA-12 is not decided here.** Which ISA-12 a 006020 interchange carries is an open question no
|
|
1858
|
+
carried source answers. Both builders write this package's default, `00501`, unless the caller
|
|
1859
|
+
supplies `interchangeControlVersion`, and both readers key on ST-03 and GS-08 and never on
|
|
1860
|
+
ISA-12.
|
|
1861
|
+
- **`06020X314` is not an adopted identifier.** 45 CFR 162.2002(c) prints the 275's guide one digit
|
|
1862
|
+
short, as `06020X314`, where 162.920(a)(19) prints `006020X314`. The conformance row adopts the
|
|
1863
|
+
162.920 spelling and records the other on its note as a typographical variant, so a 275 declaring
|
|
1864
|
+
`06020X314` is warned `X12_GUIDE_NOT_IMPLEMENTED`.
|
|
1865
|
+
- **Only the attachment data refuses to print.** A 275 attachment's BDS-03 is held in
|
|
1866
|
+
`X12AttachmentData`, whose string, JSON and `util.inspect` forms carry its octet count and no
|
|
1867
|
+
octet. Every other field of both readings, the names, member and claim identifiers and trace
|
|
1868
|
+
numbers included, is a plain string, as on every other reading in this package.
|
|
1869
|
+
- **An attachment is octets, and a string is not.** Pass an interchange carrying attachments to
|
|
1870
|
+
`parseX12` as a `Buffer`, which is read one character per octet. `serializeX12` of a built 275
|
|
1871
|
+
is a string of one character per octet: write it as latin1 (`Buffer.from(text, "latin1")`),
|
|
1872
|
+
because encoding a character above U+007F as UTF-8 makes two octets of one and BDS-02 stops being
|
|
1873
|
+
true of what was sent. Nothing inside an attachment is decoded; BDS-01 names a filter the sender
|
|
1874
|
+
applied and this package applies none.
|
|
1661
1875
|
- **No transport.** AS2, SFTP, and MLLP-style delivery are out of scope. This is a parser/serializer,
|
|
1662
1876
|
not a communications stack.
|
|
1663
1877
|
- **Published, still pre-alpha.** The package is published on npm as `@cosyte/x12` from a public
|
|
1664
1878
|
repo, but it stays on the `0.0.x`-until-first-alpha ladder. `npm view @cosyte/x12 version` is the
|
|
1665
1879
|
only source of truth for the current version, so this page does not restate one. Treat the API as
|
|
1666
1880
|
pre-alpha and pin the exact version until the first alpha.
|
|
1667
|
-
- **
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1881
|
+
- **A 276 hierarchical level whose declared parent does not resolve is left off the returned tree.**
|
|
1882
|
+
The 276 reader attaches a level by its own HL-02 and by nothing else, so a pointer naming a level
|
|
1883
|
+
that is not present, a pointer naming a level of the wrong kind, and a parent chain that returns
|
|
1884
|
+
to itself each leave that level, and everything transmitted beneath it, absent from the model. The
|
|
1885
|
+
loss is reported (`X12_276_LEVEL_DETACHED`, beside the code for the pointer defect itself), the
|
|
1886
|
+
declared pointer stays verbatim on `hierarchies`, and the segments stay verbatim on the
|
|
1887
|
+
transaction set. Nothing is re-parented onto whichever level happened to be open, because that
|
|
1888
|
+
would be this library inventing the one structure a 276 exists to state: which provider is asking
|
|
1889
|
+
about which patient's claim.
|
|
1890
|
+
- **A 276 REF, DTP or AMT short of what its row is built from loses the whole row, and says so.**
|
|
1891
|
+
Each is a record and not a slot. Without both REF-01 and REF-02 there is no reference row; without
|
|
1892
|
+
both DTP-01 and DTP-03 there is no date row, and the format qualifier that says single date or
|
|
1893
|
+
range goes with it; without a decodable AMT-02 there is no amount row. The reader builds none,
|
|
1894
|
+
fabricates nothing to stand in, and reports the loss (`X12_276_REFERENCE_ROW_DROPPED`,
|
|
1895
|
+
`X12_276_DATE_ROW_DROPPED`, `X12_AMOUNT_ROW_DROPPED`) at that segment. **The report is bounded to
|
|
1896
|
+
the row the reader tried to build.** A segment that decoded and then found no claim or service
|
|
1897
|
+
line open to sit on is a different loss, it stays silent, and it is not on any of those channels.
|
|
1898
|
+
- **The 276 reader surfaces four of the SVC elements and no postal address.** SVC-01, SVC-02, SVC-04
|
|
1899
|
+
and SVC-07 reach the typed service line; SVC-03, SVC-05 and SVC-06 are left unread, because this
|
|
1900
|
+
is the request direction and a submitter states what it billed rather than what was paid. An N3 or
|
|
1901
|
+
N4 a sender transmits under a 276 name loop reaches no typed field either, as it reaches none on
|
|
1902
|
+
the 277 beside it. All of them stay verbatim on `tx.segments`; read them there.
|
|
1903
|
+
- **A 270 hierarchical level whose declared parent does not resolve is left off the returned tree.**
|
|
1904
|
+
The 270 reader attaches a level by its own HL-02 and by nothing else, so a pointer naming a level
|
|
1905
|
+
that is not present, a pointer naming a level of the wrong kind, and a parent chain that returns to
|
|
1906
|
+
itself each leave that level, and everything transmitted beneath it, absent from the model. The
|
|
1907
|
+
loss is reported (`X12_270_LEVEL_DETACHED`, beside the code for the pointer defect itself), the
|
|
1908
|
+
declared pointer stays verbatim on `hierarchies`, and the segments stay verbatim on the transaction
|
|
1909
|
+
set. Nothing is re-parented onto whichever level happened to be open, because that would be this
|
|
1910
|
+
library inventing the one structure a 270 exists to state.
|
|
1911
|
+
- **A 270 DTP short of what a date row is built from loses the whole row, and says so.** A DTP is a
|
|
1912
|
+
record and not a slot: without both the qualifier that says what the date is for (DTP-01) and the
|
|
1913
|
+
value itself (DTP-03) there is no row to build, and the format qualifier that says single date or
|
|
1914
|
+
range goes with it. The reader builds none, fabricates nothing to stand in, and reports the loss
|
|
1915
|
+
(`X12_270_DATE_ROW_DROPPED`) at that segment, so an empty `dates` list can be told apart from a
|
|
1916
|
+
date the sender stated and this reader could build no row from. **The report is bounded to the row
|
|
1917
|
+
the reader tried to build.** A segment that would have attached to a level or an inquiry but
|
|
1918
|
+
arrives before the first HL opens one reaches no part of the model and stays SILENT, the date row
|
|
1919
|
+
included, so an empty list is evidence about a level this reader did return and about nothing else.
|
|
1920
|
+
The segments stay verbatim on the transaction set either way.
|
|
1921
|
+
- **A 270's tolerated deviations are reported once per transaction set, not once per occurrence.**
|
|
1922
|
+
A declared non-conventional delimiter raises `X12_270_NON_CONVENTIONAL_DELIMITER` once however many
|
|
1923
|
+
of the four roles deviate, and a line break between segments raises
|
|
1924
|
+
`X12_270_INTER_SEGMENT_LINE_BREAK` once however many runs the document carries. Both anchor at the
|
|
1925
|
+
ISA. The framing run is also consumed by the shared parse and recorded nowhere on the model, so
|
|
1926
|
+
only `parse270Inquiries`, which receives the bytes, can report it: `get270Inquiry` is handed the
|
|
1927
|
+
model and reports the delimiter half alone.
|
|
1928
|
+
- **Between segments, only CR and LF are absorbed. A space or a tab there costs you the whole
|
|
1929
|
+
interchange, on every transaction set.** The shared parse consumes a run of CR / LF before the next
|
|
1930
|
+
segment opens; any other whitespace becomes the head of the next segment's identifier, so `GS` is
|
|
1931
|
+
read as a non-spec segment id, no functional group frames, every segment after the ISA lands on
|
|
1932
|
+
`ix.orphanSegments` with an `X12_UNEXPECTED_SEGMENT` warning, and the interchange also reports
|
|
1933
|
+
`X12_MISSING_IEA`. Nothing is silent at the interchange level, but the typed readers see no
|
|
1934
|
+
transaction set at all: `parse270Inquiries` answers the EMPTY list, which is the same value it uses
|
|
1935
|
+
for an interchange that genuinely carries no 270, so **do not read an empty result as evidence the
|
|
1936
|
+
sender sent no inquiry without checking `ix.warnings` first.** This is long-standing shared-parse
|
|
1937
|
+
behaviour and the 270 work deliberately did not widen it: framing tolerance is shared by every
|
|
1938
|
+
transaction set, and moving it is a change to all of them rather than to one reader.
|
|
1939
|
+
- **A BDS or BIN segment's binary data is framed by the octet count its length element declares,
|
|
1940
|
+
never by delimiters, and where that count cannot be honoured it is reported, never corrected.**
|
|
1941
|
+
BDS-03 and BIN-02 are read as exactly the number of octets BDS-02 or BIN-01 declares, anywhere after
|
|
1942
|
+
the ISA, so an element, repetition or component separator, a segment terminator, a `?`, a CR or an
|
|
1943
|
+
LF inside the data is data: the segment is one segment, the data is one element, and the segments
|
|
1944
|
+
after it frame as sent. **`?` has no effect inside the declared span**, not even immediately before
|
|
1945
|
+
the terminator that follows it. `getSegmentValue`, `getAllSegmentValues` and `elementValue` return
|
|
1946
|
+
the data element verbatim, with no release unescape and no split on the repetition or component
|
|
1947
|
+
separator. **Nothing inside it is decoded**: BDS-01's filter (`B64`, for example) is not applied,
|
|
1948
|
+
and no typed reader decodes an attachment. **The count is in octets.** A `Buffer` is read one character
|
|
1949
|
+
per octet, so its count is exact; a string is counted one UTF-16 code unit per octet, which is exact
|
|
1950
|
+
at or below U+00FF, and a span holding anything above that raises `X12_BINARY_LENGTH_UNVERIFIABLE`
|
|
1951
|
+
and is still carried verbatim, so pass an interchange that carries attachments as a `Buffer`. The
|
|
1952
|
+
three ways the count can fail, each warned at the segment:
|
|
1953
|
+
- `X12_BINARY_LENGTH_INVALID`: the length element is absent, empty, or not 1 to 15 ASCII digits (a
|
|
1954
|
+
sign, a decimal point or whitespace is malformed; leading zeros are not). **No length is inferred,
|
|
1955
|
+
so this is the one case the count does not protect**: the segment is framed by its delimiters
|
|
1956
|
+
exactly as a segment of any other id is, and a delimiter inside its data splits it and can
|
|
1957
|
+
mis-frame every segment after it.
|
|
1958
|
+
- `X12_BINARY_DATA_TRUNCATED`: the input ends inside the declared span. The data element holds
|
|
1959
|
+
only the octets present and nothing past the end is read, and because the span runs to the end
|
|
1960
|
+
of the input, the transaction, group and interchange trailers are reported missing.
|
|
1961
|
+
- `X12_BINARY_LENGTH_MISMATCH`: the byte after the declared span is not the segment terminator (a
|
|
1962
|
+
length shorter or longer than the data), or the segment ends before a data element begins
|
|
1963
|
+
although a non-zero length was declared. The data element is exactly the declared span; the
|
|
1964
|
+
bytes from its end to the next terminator stay on the segment's `raw`, so a length longer than
|
|
1965
|
+
the data carries the start of the next segment into this one, and the default `serializeX12` emit
|
|
1966
|
+
still reproduces the input byte for byte.
|
|
1967
|
+
|
|
1968
|
+
**The length element is never rewritten on emit**, in either `serializeX12` mode, including where
|
|
1969
|
+
it disagrees with the data: that would be a silent correction. A span that ends exactly at the end
|
|
1970
|
+
of the input is complete and raises no binary warning; its missing terminator is supplied on emit,
|
|
1971
|
+
as for any unterminated final segment, so where a truncated span fell exactly one octet short, a
|
|
1972
|
+
re-parse of that emit reads the supplied terminator as the last octet of the data. Where `?` is the
|
|
1973
|
+
declared element separator or segment terminator, the elements before the data element are split
|
|
1974
|
+
literally, as that role's splitter already does.
|
|
1975
|
+
|
|
1976
|
+
## Code-list validity dates
|
|
1977
|
+
|
|
1978
|
+
- **🩺 A published Stop date is read as the FIRST day the code is no longer valid, and the
|
|
1979
|
+
maintainer does not say whether that is right.** `x12.org` renders a code's dates as
|
|
1980
|
+
`Start: 01/01/1995 | Last Modified: 11/01/2017 | Stop: 05/01/2018` and states nowhere whether the
|
|
1981
|
+
Stop date is the LAST day the code was valid or the FIRST day it was not. The two readings differ
|
|
1982
|
+
by exactly one day, on exactly the boundary a document produced that day sits on.
|
|
1983
|
+
|
|
1984
|
+
This package reads it as the first day the code is NOT valid, so the valid interval is half-open:
|
|
1985
|
+
a document date on or after the Stop date reports `not-valid`, and the day before it reports
|
|
1986
|
+
`valid`. The ground is the shape of the source and not a statement by the maintainer: the
|
|
1987
|
+
published dates are first-of-month publication-cycle dates, so the Stop date reads as the
|
|
1988
|
+
publication on which the code left the list rather than the last day it was on it. **That is a
|
|
1989
|
+
judgement, not a fact, and a consumer whose contract turns on the boundary day itself should
|
|
1990
|
+
confirm it with the maintainer rather than with this package.** `CARC.dates` and `RARC.dates`
|
|
1991
|
+
carry the published values unchanged, so a consumer who reads the boundary the other way has
|
|
1992
|
+
everything needed to compute it.
|
|
1993
|
+
|
|
1994
|
+
Two further bounds on the same data, neither of them a defect:
|
|
1995
|
+
- **A code with no published start date is `indeterminate`, never `valid` and never `not-valid`.**
|
|
1996
|
+
Validity is an interval and there is no interval without a start. No bundled code is in this
|
|
1997
|
+
state at the capture the dates were transcribed from; the answer exists because the fail-safe
|
|
1998
|
+
has to hold if one ever is.
|
|
1999
|
+
- **The dates describe the bundled subset and nothing wider.** A code outside it answers
|
|
2000
|
+
`indeterminate` with the inbound value echoed verbatim, which is a statement about what this
|
|
2001
|
+
package bundles rather than about what the maintainer publishes.
|
|
1671
2002
|
|
|
1672
2003
|
## Code-list `--fetch` regeneration
|
|
1673
2004
|
|
|
1674
2005
|
`pnpm refresh:code-lists` (default) validates the bundled snapshots and prints a freshness audit,
|
|
1675
2006
|
offline and CI-safe. The `--fetch` mode that would **regenerate** the full lists from their canonical
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
2007
|
+
sources is deliberately **not** run in automation: regeneration needs outbound network and is a human
|
|
2008
|
+
release step, and the tool fetches nothing and fabricates no description a maintainer has not
|
|
2009
|
+
published.
|
|
2010
|
+
|
|
2011
|
+
**Whether a bundled list's descriptions may be redistributed is answered PER LIST, and the lists do
|
|
2012
|
+
not agree.** Each bundled snapshot carries its own maintaining organisation and its own
|
|
2013
|
+
redistribution record on `meta`, so a consumer deciding whether a description is theirs to display,
|
|
2014
|
+
cache or re-publish reads that list's answer rather than a single sentence covering all seven:
|
|
2015
|
+
|
|
2016
|
+
| Bundled list | External code list | Maintained by | Redistribution | Approach for permission |
|
|
2017
|
+
| ------------------------------------- | ------------------ | ------------- | --------------------- | ----------------------- |
|
|
2018
|
+
| CARC (Claim Adjustment Reason Codes) | 139 | ASC X12 | licence required | ASC X12 (see below) |
|
|
2019
|
+
| RARC (Remittance Advice Remark Codes) | 411 | CMS | permitted, no licence | none needed |
|
|
2020
|
+
| CSCC (Claim Status Category Codes) | 507 | ASC X12 | licence required | ASC X12 (see below) |
|
|
2021
|
+
| CSC (Claim Status Codes) | 508 | ASC X12 | licence required | ASC X12 (see below) |
|
|
2022
|
+
| Service type (EB-03) | 958 | ASC X12 | licence required | ASC X12 (see below) |
|
|
2023
|
+
| CLP-02 claim status | none | ASC X12 | **not established** | ASC X12 (see below) |
|
|
2024
|
+
| INS-03 maintenance type | none | ASC X12 | **not established** | ASC X12 (see below) |
|
|
2025
|
+
|
|
2026
|
+
The **External code list** column is the list's id on the X12 External Code Lists index. It is the
|
|
2027
|
+
column that decides the one beside it: a list with a row there is answered from that row, and only a
|
|
2028
|
+
list with no row can be one the carried sources never name. `none` means exactly that the index
|
|
2029
|
+
publishes no row for the list, not that the list is unimportant.
|
|
2030
|
+
|
|
2031
|
+
**The approach, for every row that needs one:** ASC X12, which publishes that it is the only
|
|
2032
|
+
organisation authorised to grant permission for the use of X12 products. Permission to reproduce X12
|
|
2033
|
+
intellectual property is requested through the licensing programme X12 publishes at
|
|
2034
|
+
<https://x12.org/products/licensing-program>, by email to the intellectual-property address given
|
|
2035
|
+
there, naming the requester and their organisation and describing both the artifact and its intended
|
|
2036
|
+
distribution. Subscriptions to X12-maintained code lists are bought through the Code List Update
|
|
2037
|
+
Subscription page linked from <https://x12.org/codes>.
|
|
2038
|
+
|
|
2039
|
+
The evidence behind each row is quoted on the list itself, at `meta.redistribution.terms`. In short:
|
|
2040
|
+
the X12 External Code Lists index records CARC as external code list 139, the two claim-status lists
|
|
2041
|
+
as 507 and 508, and the service type codes as 958, all maintained by an X12 code maintenance
|
|
2042
|
+
committee group, under the statement that all X12 work products are copyrighted and that
|
|
2043
|
+
subscriptions to X12-maintained code lists are purchased. X12's own intellectual-property policy,
|
|
2044
|
+
reproduced in HL7's CARIN Consumer Directed Payer Data Exchange code system stubs, adds that all X12
|
|
2045
|
+
products are subject to it and that X12 is the only organisation authorised to grant permission for
|
|
2046
|
+
their use. The same index records RARC as external code list 411 maintained by CMS, and HL7's CARIN
|
|
2047
|
+
terminology licensure page puts CARC among the code systems that require a purchased licence and RARC
|
|
2048
|
+
among those requiring none.
|
|
2049
|
+
|
|
2050
|
+
**Being cited from a TR3 is not evidence of a missing publisher.** Three bundled lists point their
|
|
2051
|
+
`meta.source` at a purchased Technical Report Type 3: the service type codes, the CLP-02 dispositions
|
|
2052
|
+
and the INS-03 maintenance types. Only the last two are absent from the External Code Lists index;
|
|
2053
|
+
the service type codes have a row there, so they are answered from it. Where a bundled subset was
|
|
2054
|
+
read is a different question from what the publisher publishes, and only the second decides the
|
|
2055
|
+
terms.
|
|
2056
|
+
|
|
2057
|
+
**"Not established" is a recorded answer here, not a gap waiting to be tidied.** The last two lists,
|
|
2058
|
+
the CLP-02 dispositions and the INS-03 maintenance types, are printed inside a purchased ASC X12
|
|
2059
|
+
Technical Report Type 3 and have no row on the External Code Lists index at all, and no source
|
|
2060
|
+
obtained for this package names them or states whether their descriptions may be redistributed. They
|
|
2061
|
+
are therefore treated as **not redistributable** wherever a permission decision is made, exactly as a
|
|
2062
|
+
licence-restricted list is: an unsettled question is never read as a permission.
|
|
2063
|
+
|
|
2064
|
+
Consequences you can rely on:
|
|
2065
|
+
|
|
2066
|
+
- **A list whose descriptions may not be redistributed stays exactly the cited part it already
|
|
2067
|
+
ships.** Nothing is enlarged, refetched or relicensed by recording the terms, and the record names
|
|
2068
|
+
the licensor who could change that.
|
|
2069
|
+
- **`--fetch` answers each list on its own terms.** It reports each bundled list's regeneration
|
|
2070
|
+
permission independently, refuses only the lists whose own record forbids it, prints the licensor
|
|
2071
|
+
to approach beside each refusal, and never refuses a list because a different list is restricted.
|
|
2072
|
+
It exits `2` while any list is refused and `0` when none is.
|
|
2073
|
+
- **Snapshot validation refuses an unlabelled list.** A bundled list carrying no maintaining
|
|
2074
|
+
organisation, or no redistribution record, fails `pnpm refresh:code-lists` with a message naming
|
|
2075
|
+
that list, so it cannot reach a release unlabelled.
|
|
2076
|
+
- **`codeListRedistributionIsPermitted(meta)` is the single decision point**, and it is exported.
|
|
2077
|
+
Only a recorded permission answers `true`; a licence requirement, an unsettled status and a missing
|
|
2078
|
+
record all answer `false`.
|
|
1680
2079
|
|
|
1681
2080
|
---
|
|
1682
2081
|
|