docs(sp3): fix rule IDs (R034/R035) and BHT06 naming in plan+spec
This commit is contained in:
@@ -9,56 +9,78 @@
|
||||
|
||||
## Phase 1 — 837P extra validation rules
|
||||
|
||||
### Task 1: REF*G1 enforcement rule (R032)
|
||||
> **Note on rule IDs:** R032 and R033 are already used in `validator.py`
|
||||
> for CLM05-2 facility code qualifier and CLM05-1 place of service code
|
||||
> respectively. The two new rules in this phase use **R034** (REF*G1
|
||||
> enforcement) and **R035** (BHT06 transaction type code).
|
||||
|
||||
### Task 1: REF*G1 enforcement rule (R034)
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/src/cyclone/parsers/validator.py`
|
||||
|
||||
**Detection mechanism:** `ClaimOutput.raw_segments` is already populated
|
||||
by the parser, so R034 scans `raw_segments` for any segment whose first
|
||||
two elements are `["REF", "G1", ...]`. No new model field is required.
|
||||
|
||||
- [ ] **Step 1: Add failing tests**
|
||||
|
||||
Append to `backend/tests/test_validator.py`:
|
||||
|
||||
```python
|
||||
def test_r032_ref_g1_required_when_freq_7_no_ref_g1_emits_error(co_medicaid_payer_with_ref_g1_required):
|
||||
# ... claim with frequency_code=7, no REF*G1
|
||||
def test_r034_ref_g1_required_when_freq_7_no_ref_g1_emits_error(strict_ref_g1_payer):
|
||||
# ... claim with frequency_code=7, no REF*G1 in raw_segments
|
||||
# expect validation error
|
||||
|
||||
def test_r032_ref_g1_required_when_freq_8_no_ref_g1_emits_error(co_medicaid_payer_with_ref_g1_required):
|
||||
# ... claim with frequency_code=8, no REF*G1
|
||||
def test_r034_ref_g1_required_when_freq_8_no_ref_g1_emits_error(strict_ref_g1_payer):
|
||||
# ... claim with frequency_code=8, no REF*G1 in raw_segments
|
||||
# expect validation error
|
||||
|
||||
def test_r032_ref_g1_required_when_freq_7_with_ref_g1_passes(co_medicaid_payer_with_ref_g1_required):
|
||||
# ... claim with frequency_code=7, REF*G1 present
|
||||
def test_r034_ref_g1_required_when_freq_7_with_ref_g1_passes(strict_ref_g1_payer):
|
||||
# ... claim with frequency_code=7, REF*G1 present in raw_segments
|
||||
# expect no error
|
||||
|
||||
def test_r032_ref_g1_required_when_freq_1_no_ref_g1_passes(co_medicaid_payer_with_ref_g1_required):
|
||||
def test_r034_ref_g1_required_when_freq_1_no_ref_g1_passes(strict_ref_g1_payer):
|
||||
# ... claim with frequency_code=1, no REF*G1
|
||||
# expect no error (rule only fires on 7/8)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
- [ ] **Step 3: Implement `_r032_ref_g1_required` in `validator.py`**
|
||||
- [ ] **Step 3: Implement `_r034_ref_g1_required` in `validator.py`**
|
||||
- Scan `claim.raw_segments` for `["REF", "G1", *]`; only check if claim
|
||||
frequency is 7 or 8; only emit if `cfg.require_ref_g1_for_adjustments`.
|
||||
- [ ] **Step 4: Register in `_RULES` list**
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
### Task 2: BHT06 transaction-set-purpose-code rule (R033)
|
||||
### Task 2: BHT06 transaction-type-code rule (R035)
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/src/cyclone/parsers/validator.py`
|
||||
- Modify: `backend/src/cyclone/parsers/models.py` (add `Envelope.transaction_type_code: str | None`)
|
||||
- Modify: `backend/src/cyclone/parsers/parse_837.py` (populate `transaction_type_code` from BHT06 in `_build_envelope`)
|
||||
|
||||
- [ ] **Step 1: Add failing tests**
|
||||
> **Note on naming:** BHT06 in the 837P 005010X222A1 implementation is the
|
||||
> "Transaction Type Code" element (qualifier 640) — not the "Transaction
|
||||
> Set Purpose Code" (which is BHT02, qualifier 353). The plan originally
|
||||
> conflated these. Use `transaction_type_code` for the new `Envelope` field.
|
||||
|
||||
- [ ] **Step 1: Add failing tests** — frequency_code=7/8 with no REF*G1 in raw_segments should NOT fire R034 (R034 is gated on `cfg.require_ref_g1_for_adjustments`, which is False for CO). Test must use a "strict" config.
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
- [ ] **Step 3: Implement `_r033_bht06_allowed` in `validator.py`**
|
||||
- [ ] **Step 4: Register in `_RULES` list**
|
||||
- [ ] **Step 5: Commit**
|
||||
- [ ] **Step 3: Add `transaction_type_code: str | None = None` to `Envelope` model**
|
||||
- [ ] **Step 4: Populate it in `_build_envelope` from `seg[6]` when present**
|
||||
- [ ] **Step 5: Implement `_r035_bht06_allowed` in `validator.py`**
|
||||
- If `claim.envelope.transaction_type_code` is set and not in
|
||||
`cfg.allowed_bht06`, emit error.
|
||||
- [ ] **Step 6: Register in `_RULES` list**
|
||||
- [ ] **Step 7: Commit**
|
||||
|
||||
### Task 3: Verify existing R031 (REF*G1 optional) keeps warning behavior
|
||||
### Task 3: Verify existing R031 (REF*G1 optional) keeps no-op behavior
|
||||
|
||||
**Files:**
|
||||
- Verify: `backend/src/cyclone/parsers/validator.py:54-57`
|
||||
|
||||
- [ ] **Step 1: Read current `_r031_ref_g1_optional`**
|
||||
- [ ] **Step 2: Confirm it stays as a warning for default configs**
|
||||
- [ ] **Step 2: Confirm it stays as a no-op (returns empty tuple)**
|
||||
- [ ] **Step 3: (No commit — verification task)**
|
||||
|
||||
### Task 4: Wire `require_ref_g1_for_adjustments` into CO Medicaid factory
|
||||
@@ -66,9 +88,9 @@ def test_r032_ref_g1_required_when_freq_1_no_ref_g1_passes(co_medicaid_payer_wit
|
||||
**Files:**
|
||||
- Verify: `backend/src/cyclone/parsers/payer.py:67`
|
||||
|
||||
- [ ] **Step 1: Confirm factory sets the flag for CO**
|
||||
- [ ] **Step 2: Run existing co_medicaid fixture through new R032**
|
||||
- [ ] **Step 3: Adjust fixture if false positives appear**
|
||||
- [ ] **Step 1: Confirm factory sets the flag for CO (currently `False` for v1 leniency)**
|
||||
- [ ] **Step 2: Run existing co_medicaid fixture through new R034**
|
||||
- [ ] **Step 3: Adjust fixture or factory if false positives appear**
|
||||
- [ ] **Step 4: Commit if any change**
|
||||
|
||||
### Task 5: Phase 1 commit + full suite
|
||||
|
||||
Reference in New Issue
Block a user