Rule types & applicator
Outcome
You know exactly what each rule type does, the order the applicator runs them in, and which combinations are safe vs. which produce surprising output.
Prerequisites
A working understanding of the editor (7.1 — The companion guide editor). Familiarity with X12 segment structure (9.2 — Segment cheat-sheet).
The four rule types
| Type | What it does | Most common use |
|---|---|---|
override | Replaces the value of an element with a literal, a template, or a computed expression. | Payer wants NM109 to carry their proprietary ID instead of NPI. |
suppress | Removes a segment, loop, or element. | Payer rejects a 2310 rendering provider when the rendering provider equals the billing provider. |
append | Inserts a new segment at a defined position. | Payer requires a payer-specific K3 segment in 2300. |
validate | Asserts that an element / segment matches an expression; fails outbound generation if not. | Payer's billing provider taxonomy must match a fixed set. |
The applicator order
The applicator runs in a deterministic order so two guides producing overlapping rules give the same result every time:
Why this order:
- Validate first — if the input is unfit, fail before mutating anything.
- Suppress second — removing segments first means override / append selectors do not have to handle "may not exist".
- Override third — operates on the surviving segments only.
- Append last — newly inserted segments cannot themselves be validated / suppressed / overridden by the same guide.
Code reference: packages/x12/src/companion-guides/applicator.ts.
Selector syntax
All rules use the same selector grammar:
<segmentId>[<index>][.<elementIndex>][:<subElementIndex>]
Examples:
| Selector | Matches |
|---|---|
NM1 | Every NM1 segment in the transaction. |
NM1[NM101=85] | The NM1 whose first element equals 85 (billing provider). |
NM1[NM101=85].NM109 | The 9th element of the billing-provider NM1. |
CLM[loop=2300].CLM05:1 | The 1st sub-element of CLM05 in the 2300 loop. |
2400.LX[1].SV1.SV101 | The first element of the SV1 in line 1 of loop 2400. |
A selector that matches more than one segment applies to all matches (common for the 2400 loop where every line gets the same override).
Override values
Override values can be one of:
| Form | Example | Meaning |
|---|---|---|
| Literal | "PRX" | The literal string. |
| Template | "{billingProvider.taxonomy}" | A {path} reference into the source claim record. |
| Expression | "upper({patient.lastName})" | A small expression DSL — upper, lower, pad-left, slice, concat. |
The full expression DSL is documented inline in applicator.ts as the
evaluateValue function.
Validate expressions
Validate rules use the same expression grammar plus comparators:
| Operator | Example | Meaning |
|---|---|---|
eq | eq({NM109}, "1234567890") | Element equals literal. |
match | match({NM103}, "^[A-Z]+$") | Element matches regex. |
oneOf | oneOf({NM101}, ["IL", "QC"]) | Element is in set. |
len | len({NM103}) >= 1 | Length comparison. |
and / or / not | and(match({NM109}, "^\\d{10}$"), oneOf({NM108}, ["XX"])) | Boolean composition. |
Failed validations halt outbound generation with a structured error
record that the operator can read on /transactions/:id.
Common patterns
Payer-specific provider ID
rule_type: override
location: 2010AA.NM1[NM101=85].NM109
value: "{billingProvider.payerSpecificId.UHC}"
note: UHC requires their proprietary submitter ID, not NPI.
Suppress redundant rendering provider
rule_type: suppress
location: 2310B
condition: "eq({billingProvider.npi}, {renderingProvider.npi})"
note: Some payers reject when rendering equals billing.
Append payer-required K3
rule_type: append
location: 2300.HI[*]+1
segment: K3*OHIODOH-PSC*0~
note: Ohio DOH requires a K3 carrying the program specifier.
Validate taxonomy
rule_type: validate
location: 2010AA.PRV[PRV01=BI].PRV03
expression: oneOf({PRV03}, ["171M00000X", "171R00000X", "183500000X"])
note: Anthem only accepts a fixed taxonomy set for IDD waiver claims.
Multi-guide composition
A trading partner can have multiple guides active at once (e.g. one for state Medicaid, one for the clearinghouse layered on top). The companion-guide-resolver in edi-gateway picks the active set based on effective dates; the applicator runs each guide's rule set in partner- declared order. Conflicts across guides resolve last-wins per location.
See apps/edi-gateway/src/service/companion-guide-resolver.ts.
Validation
| Check | Expected |
|---|---|
validate rules halt generation when they fail | Yes — the transaction record carries the structured error. |
suppress removes the segment everywhere | Yes — confirm via the live preview's "appliedRules" list. |
override does not silently fail when the path does not exist | Correct — a non-matching selector is logged and the rule is treated as SKIPPED. |
| Multi-guide order matches partner declaration | Yes — see the Resolver chain tab on the trading partner detail page. |
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Override applied to too many segments | Selector is loose | Add a qualifier (e.g. NM1[NM101=85] instead of NM1). |
| Append produces a segment in the wrong order | Position selector mis-spelled | Use +1 to mean "after the matched anchor"; -1 for "before". |
| Validate expression always passes | Expression has no comparison (e.g. just a path reference) | Wrap in an explicit comparator like eq(…, …). |
| Rule has no effect at runtime but works in preview | Guide's effective window does not include today, or the partner's resolver chain places another guide last that re-overrides | Inspect the resolver chain. |