Skip to content

Read 835 remittance advice (005010X221A1) - #4

Merged
IPerception merged 1 commit into
mainfrom
feat/x221-835-read
Aug 16, 2026
Merged

Read 835 remittance advice (005010X221A1)#4
IPerception merged 1 commit into
mainfrom
feat/x221-835-read

Conversation

@IPerception

Copy link
Copy Markdown
Owner

Adds reading support for 835 remittance advice: loop resolution, inspector naming, and three balancing checks. No payments table, no CSV export, no Limited Data Set — those are deliberately left for later.

Why this one does not follow the PACDR pattern

PACDR's rule was detected → do more, never do differently, and it held because 005010X298 is structurally the same transaction as the 837P. It does not hold here. A probe of a hand-written 835 through the current build found the tree actively wrong, not merely incomplete:

  • LX opened a group labelled "Line 1" — in an 835 it opens loop 2000, a grouping of claims.
  • NM1*82 opened "Rendering provider" and swallowed both SVC loops and PLB, a transaction-level segment that must never sit inside a claim.

So for an 835 the 837 anchors are switched off and replaced, gated on ST-01 per transaction. What survives from PACDR is the gating discipline: a file with no 835 in it runs exactly the code it ran before, and a mixed interchange resolves each transaction correctly. 835 loop ids are deliberately kept out of ENTITY_LOOPS/ANCHOR_LOOPS — the omission is load-bearing, and makes the 837 fallback inert by construction.

The three checks

All warnings, never errors, each standing down rather than guessing when a figure is absent or unreadable.

Level Rule
Line SVC-02 − adjustments in that 2110 = SVC-03
Claim CLP-03 − every CAS on the claim = CLP-04
Transaction BPR-02 = Σ CLP-04 − Σ PLB-04

The last one reads backwards on purpose: a positive PLB-04 reduces what the payer pays. It is the line most likely to be "corrected" into a bug, so it carries three separate treatments — a comment at the subtraction, docs/835-validation.md explaining why, and a test named for the convention. The test asserts the finding's detail text, not just that a finding fires: a flipped sign still produces a finding, only with the wrong number in it, so a pass/fail-only test would not catch the regression. Verified by flipping the sign and watching the suite go red.

Reversals (CLP-02 = 22) balance under the same rules with no CLP-02 gate anywhere. The fixture's second claim is a reversal carrying negative amounts throughout.

Also fixed, found in review

  • A dropped segment. An 835 N1 whose qualifier was not PR/PE returned without pushing a leaf, so the segment vanished from the tree and from the interchange's own count — invisible to every existing assertion, since a missing segment breaks no structure. Now falls through to a plain leaf as NM1 already did, pinned by a test that fails on the one-word revert.
  • The Checks panel told an 835 user that each claim's CLM-02 reconciled — on a file with no CLM in it — while saying nothing about the three checks that actually ran.
  • The Outline gave an 835 no per-claim navigation. It matters because the rail also scopes find & replace, and for the legal no-LX remittance the whole file collapsed to a single unselectable node.

Verification

All 8 browser suites and the 11 Python tests pass. Tree 142→167, validate 74→93, deid 123→126, claims 106→108, outline 60→65; parity untouched at 77 and unaffected by construction — everything new inside the engine markers is reachable only from validateDocument, which parity never calls.

Existing 837P and PACDR assertions are unchanged — none was edited to make anything pass.

Sources

The X12 TR3 is paywalled and was not read, and no companion guide was used for this pass. What is asserted is limited to loop ids, segment ids, element positions and the balancing arithmetic the transaction's own definition implies. Every unconfirmed item is either cut (Σ SVC-03 = CLP-04) or stands down (debit and zero-payment transactions). The fixture is wholly invented.

🤖 Generated with Claude Code

An 835 is a different transaction, not a variant of the 837 the app was
built around, and the default path did not merely miss its structure --
it fabricated 837 structure over it. `LX` opened a group labelled
"Line 1" when in an 835 it opens loop 2000, a grouping of claims; `NM1*82`
opened "Rendering provider" and swallowed both service lines and `PLB`,
a transaction-level segment that must never sit inside anything.

So for an 835 the 837 anchors are switched off and replaced, gated on
`ST-01` per transaction: a file with no 835 in it runs exactly the code
it ran before, and a mixed interchange resolves each transaction
correctly. 835 loop ids are deliberately absent from `ENTITY_LOOPS` and
`ANCHOR_LOOPS`, which makes the 837 fallback inert by construction.

Reading only, as scoped: loop resolution, segment and qualifier naming
for the inspector, a separate 835 reference block, and three balancing
checks -- line, claim, and transaction -- all warnings, each standing
down rather than guessing when a figure is absent or unreadable. No
payments table, no CSV export, no Limited Data Set.

The transaction check is `BPR-02 = SUM(CLP-04) - SUM(PLB-04)`: a
positive `PLB-04` reduces what the payer pays. That reads backwards and
is the line most likely to be "corrected" into a bug, so it carries a
comment, an explanation in docs/835-validation.md, and a test named for
the convention that asserts the finding's detail text -- a flipped sign
still produces a finding, just with the wrong number in it.

Reversals (`CLP-02 = 22`) balance under the same rules with no special
case anywhere; the fixture's second claim is one, carrying negative
amounts throughout. The Claims tab is empty for an 835 by design and
the Limited Data Set does not reach its patient identifiers -- both
audited rather than assumed, and both pinned by tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@IPerception
IPerception merged commit 940ba62 into main Aug 16, 2026
1 check passed
@IPerception
IPerception deleted the feat/x221-835-read branch August 21, 2026 01:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant