# 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 = ""` 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.