From 9e422fdadb0bb84bffd929faa4be93adf346af59 Mon Sep 17 00:00:00 2001 From: Nora Date: Wed, 8 Jul 2026 22:27:21 -0600 Subject: [PATCH] feat(sp24): expose PATIENT_LOOP_DEFAULT_INCLUDED constant in serialize_837 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Promotes the default value of _build_subscriber_block(include_patient_loop=...) from a hardcoded True (the broken IG-incorrect state that emitted HL*3 / PAT*01 / NM1*QC for SBR02='18' claims) to a public module-level constant PATIENT_LOOP_DEFAULT_INCLUDED = False (the IG-correct state). Per X12 005010X222A1, the 2000C Patient Hierarchical Level MUST be absent when SBR02 == '18' (Self-pay, the CO-Medicaid IHSS workflow). The previous default of True emitted the forbidden 2000C block on every self-pay claim, which Edifabric rejected with '2000C HL must be absent when 2000B SBR02 = "18"'. Also adds __all__ to the module so PATIENT_LOOP_DEFAULT_INCLUDED is documented as part of the public surface. The IG-correctness guard (see cyclone.reissue.ig_correctness_check in the next commit) reads this constant rather than inspect.signature'ing _build_subscriber_block — that handle survives any future refactor of the helper. --- backend/src/cyclone/parsers/serialize_837.py | 26 +++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/backend/src/cyclone/parsers/serialize_837.py b/backend/src/cyclone/parsers/serialize_837.py index e3a2ba6..fc2d3c9 100644 --- a/backend/src/cyclone/parsers/serialize_837.py +++ b/backend/src/cyclone/parsers/serialize_837.py @@ -52,6 +52,14 @@ from types import SimpleNamespace from cyclone.parsers.models import ClaimOutput +__all__ = [ + "PATIENT_LOOP_DEFAULT_INCLUDED", + "SerializeError", + "serialize_837", + "serialize_837_for_resubmit", + "serialize_member_week_batch", +] + _SEG = "~" _ELEM = "*" _ISA_COMPONENT_SEPARATOR = ":" @@ -64,6 +72,22 @@ class SerializeError(Exception): """Raised when a claim cannot be serialized.""" +#: Default value for ``_build_subscriber_block(include_patient_loop=...)``. +#: +#: Per X12 005010X222A1, the 2000C Patient Hierarchical Level +#: (``HL*3 → PAT → NM1*QC``) is REQUIRED only when Patient != Subscriber +#: (i.e. ``SBR02 != "18"``). When ``SBR02 == "18"`` (Self-pay, the +#: CO-Medicaid IHSS workflow), the 2000C loop MUST be absent — +#: otherwise Edifabric / pyX12 reject the file with +#: ``2000C HL must be absent when 2000B SBR02 = "18"``. +#: +#: The regression test +#: ``tests/test_serialize_837.py::test_serialize_837_patient_loop_default_is_false`` +#: pins this value to ``False``. Flipping it back to ``True`` requires +#: an explicit PR-level discussion (SP24 2026-07-08). +PATIENT_LOOP_DEFAULT_INCLUDED: bool = False + + # --------------------------------------------------------------------------- # Envelope helpers # --------------------------------------------------------------------------- @@ -502,7 +526,7 @@ def _build_subscriber_block( subscriber, claim_filing_indicator_code: str | None, payer=None, - include_patient_loop: bool = True, + include_patient_loop: bool = PATIENT_LOOP_DEFAULT_INCLUDED, ) -> list[str]: """Loop 2000B (HL*2) → SBR → 2010BA (NM1*IL) → 2010BB (NM1*PR).