Files
ecw-charge-validation/docs/superpowers/specs/2026-10-07-dental-claims-run-all-conditions-design.md
ManikandanandClaude Opus 5.5 ba15a574ab Initial import: eCW Charge Validation bot and results Portal
Snapshot of the working project as of 2026-10-23 (local 2d4d4fc), one
commit with no earlier history: the tracked files were de-identified
first (synthetic claim ids and patient data only; see Context.md
section 7). Credentials, run logs, screenshots, claim reports and client
workbooks are gitignored and not included.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 18:38:17 +05:30

138 lines
7.1 KiB
Markdown

# Dental claims run every applicable condition — design
Date: 2026-10-07. Status: approved in chat (operator, 2026-10-07);
implemented 2026-10-12 (operator: "this is our number one condition").
## 2026-10-12 update (as built)
- The rule now also covers #12 (H codes: BH payer → modifier removed;
any other payer → line unchecked + fee 0) and #14 (Medicare: G8510 /
G8431 unchecked + fee 0, #6 not run). Both run on Dental claims like
every other condition; #12's BH path has no modifier column to read on
the Dental grid, so it never fires there.
- A fix the Dental screen cannot hold → **Review** (operator): a condition
module declares `DENTAL_UNSUPPORTED = "<reason>"` and `run_all` records
that reason instead of applying it on a `screen == "dental"` read —
telehealth, medicare_telehealth, vaccine_admin_codes.
- Dental claims are **never saved** in this change (operator), whatever
`SAVE_CORRECTIONS` says; the review-before-close box still shows.
- A Dental claim is read and run through the conditions even with
CHECK_HIGH_RISK and CHECK_SLIDING_FEE both off (it used to come back
blank).
- The Charge Summary applies the same claim-level checks (note read, CPT /
ICD rows read, conditions run) to a Dental read as to UB/HCFA.
- Row selectors gained a third (Dental) alternative, scoped to the Dental
window on screen (`:visible`); `extract()` returns `screen`
("ub" / "hcfa" / "dental").
- Not live-verified yet: the first live run should be SAVE-off on a few
Dental claims (one with DCONS or Dscprit).
## Rule (operator, 2026-10-07)
Every claim is checked against **every condition whose Payer column is
"All" / "All payers"**, **plus** every condition specific to that claim's
payer (Medicare, Medicaid, Dental payers, ...). This holds for every payer
and every claim screen — UB, HCFA and Dental alike.
UB and HCFA claims already work this way: each claim runs the whole
registry (`conditions/__init__.py` `CONDITIONS`) and each condition's own
`detect()` decides from the claim's codes and payer. **The gap is Dental:** a
Dental claim today runs only #15 high risk and #8 sliding fee and never
reaches `run_all`. So, for example, `dummy_codes` (DCONS/Dscprit, which are
Dental codes) can never fire on any claim.
## What a Dental claim will run
| Doc # | Condition | Payer (document) | Module |
|---|---|---|---|
| 5 | J2930/J2001 uncheck + fee 0 | ALL | `j2930_j2001_update` |
| 6 | Depression DX pointer | All | `depression_dx_pointer` |
| 7 | Zero-fee uncheck / priced line check | ALL | `zero_fee_uncheck`, `priced_line_check` |
| 21 | Telehealth POS 2 + modifier | All | `telehealth` |
| 22 | Medicare telehealth G2025 | Medicare | `medicare_telehealth` |
| 18 | Vaccine admin codes | All except Medicare | `vaccine_admin_codes` |
| 8 | DCONS/Dscprit uncheck + fee 0 | All Dental Payer | `dummy_codes` |
| 8 | Sliding fee date check | All Dental Payer | `pages/sliding_fee` (unchanged) |
| 15 | High risk in Billing Notes | Dental Payers | `pages/dental_notes` (unchanged) |
No condition gains a form-type check: each still decides from codes and
payer only. A condition whose codes are not on the claim does nothing.
## Dental screen facts (from Dom.txt, claim screen `.modal[id^="dentalClaim"]`)
- CPT/CDT grid `table[id^="claimCPTCodesTable"]`; real rows are
`tr[ng-repeat^="CPT in CPTCodes"]` (no `CPTROW_` id).
- Per row: checkbox `[ng-click*="updateBillToIns("]` (same as UB/HCFA), code
`[data-fieldname="web_cptcode"]`, pointers `web_icd1`..`web_icd4`, units
`web_units`, fee `web_billedFee` (blur runs `editCPTRow('BILLED_FEE')`),
DOS `DentalClaimCPTSDOS`.
- **No per-row POS and no modifier columns.** POS is claim-level
(`ng-model="ClaimData.pos"`).
- Prog. Notes button `button[ng-click="viewProgNote()"]`
(`dentalClaimProgressNoteBtn…`) — the existing `SEL_PROGRESS_NOTES` matches.
- Insurance grid: `#DentalClaimTbl2` (Bill To, Ins Id, Name, ...).
- Billing Notes: `#dentalClaimNotes` (already read by high risk).
None of the row fields has been exercised live yet; Dom.txt is one capture.
## Design
1. **Selectors** (`selectors/claim_form.py`): add the Dental alternative to
each row selector the helpers already use — `SEL_CPT_ROWS`,
`SEL_CPT_CODE`, `SEL_CPT_ICD1..4`, `SEL_CPT_BILLED_FEE`, `SEL_CPT_UNITS`.
The Dental row selector is scoped under `.modal[id^="dentalClaim"]` so it
cannot match a grid on another screen. Within one row only one alternative
ever matches, the same contract the UB/HCFA pairs rely on.
2. **Reader** (`pages/claim_form.py` `_EXTRACT_JS`): read Dental rows into the
same `cpt` row shape (`code`, `icd1..4`, `units`, `billed_fee`, `billed`,
`sdos`; `pos`/`mod1..4` empty), insurance from `#DentalClaimTbl2`, the
Dental claim number, ICD list, and `notes` from `#dentalClaimNotes`.
One `extract()` for all three screens.
3. **Flow** (`flows/export_medcor_ready.py`): a Dental claim runs high risk +
sliding fee first (unchanged, read-only), then the same path as UB/HCFA:
`extract()`, Prog. Notes (when `OPEN_PROGRESS_NOTES`), `run_all`, per-claim
box, Charge Summary. The Dental results stay on the claim's data so the box
and the summary show both.
4. **A fix the Dental screen cannot make** — e.g. telehealth needs a row
modifier and the Dental grid has none, or POS is claim-level: the condition
returns `declined(...)` with the reason ("Dental screen has no modifier
column"), so the claim is **Review** in the Charge Summary. Never a silent
skip, never a guess.
5. **Charge Summary**: one row per claim combining condition comments with the
Dental findings (HIGH RISK, sliding fee). Category: Review beats Fail beats
Pass, as today.
6. **Saving**: Dental claims are **never saved** in this change, whatever
`SAVE_CORRECTIONS` says. Their corrections are shown and listed as
"Corrections pending (not saved)". Dental save is enabled only after a live
verification-mode run confirms the row writes.
## Error handling
- Dental form not loaded (`wait_claim_loaded`): conditions skipped, claim is
Review — same as HCFA today.
- A Dental row field missing (fee or checkbox not found): the existing helpers
already treat a missing field as unknown, not as zero/unchecked.
- High risk / sliding fee failures keep their current Review handling.
## Testing
- Grow `tests/fixtures/dental_claim.html` from Dom.txt's real Dental grid
(rows, checkbox, fee, pointers, insurance grid, Prog. Notes button) with no
patient data.
- `extract()` on the Dental fixture returns the expected `cpt` and `insurance`.
- Per condition, a Dental case: dummy codes (DCONS/Dscprit) uncheck + zero;
J2001 uncheck + zero; zero-fee uncheck; priced line check; depression
pointer retag on `web_icd*`; telehealth on Dental → declined/Review.
- Flow: a Dental claim gets high risk + sliding fee **and** condition results
in one summary row; never offered Save.
- Full suite stays green.
- Live: one SAVE-off run on Dental test claims (with a DCONS or Dscprit line)
before Dental save is considered.
## Out of scope
- New document conditions not yet built (#3, #4, #9-#14, #16, #19, #20,
#23-#55).
- Saving Dental claims.
- "Special programs" half of #8.