accelerando.wiki ↗ app ↗ github

Medical Billing (Revenue Cycle)

The rules are published. The contracts are signed. The denial codes mean what they say.

Medical billing *looks* non-deterministic. It isn't. The hard part is keeping up with the thousands of payer-specific rules that change every quarter. This module starts with the deterministic spine — payer contracts, fee schedules, claims, denials routed by group code — and leaves room for the AI-rule-generation loop (slice C and beyond).


The three views

Claims — every claim with status, billed/paid/patient-responsibility, denial count, and days-in-AR. Click a row for the drawer (submit, post-denial actions).

Denial queue — open denials sorted by routing action. Each denial shows its X12 835 group code, reason code, dollar amount, and the deterministic action it was routed to.

Payer contracts — signed agreements with timely-filing and appeal windows. AR aging by payer below.


The four-way denial router

Every X12 835 CAS denial carries a group code. The router is deterministic — no AI, no judgment, no negotiation.

| Group | Meaning | Action | |---|---|---| | CO | Contractual Obligation | Write off per contract | | CO-29 | Timely filing expired | Mandatory write-off + process review flag | | OA | Other Adjustment | Flag for human review | | PR | Patient Responsibility | Bill the patient | | PI | Payer Initiated | Internal adjustment, no action |

The rule doesn't suggest. The rule enforces. CO-29 is the only branch — it gets its own action so the process gap that let the timely-filing window slip is flagged for review *in addition to* the write-off.


The submit-time timely-filing guard

submit_claim runs the timely-filing check against the payer contract *before* flipping status to submitted. Past the window? The submission is refused with mandatory_write_off_timely_filing — the only honest disposition.

Standard windows (preload these as PayerContract records):

| Payer | Timely filing | Appeal window | |---|---|---| | BCBS | 180 days | 180 days | | Medicare | 365 days | 120 days | | Medicaid | 90 days | 90 days |

The rule is enforced, not advisory. You don't get to "submit anyway and see what happens." That's how CO-45 writeoffs happen.


Fee schedule lookup

add_claim_line looks up the contracted allowed amount from the active fee schedule for the claim's payer + this CPT + modifier. If no entry exists, allowed_amount is 0 and fee_schedule_missing is returned — the operator-facing UI surfaces this so you don't submit a claim without knowing what you'll be paid.

contractual_adjustment = billed - allowed. The number is in the contract; the system enforces it.


AR aging — the dashboard everyone actually opens

ar_aging_by_payer buckets unpaid submitted claims at 30/60/90/120+ days from DOS, grouped by payer. The 120+ bucket renders red because at that point the claim is approaching the timely-filing-on-appeal cliff for most payers.

SELECT payer_id,
       COUNT(*) AS claims,
       SUM(... 0..30   ...) AS current,
       SUM(... 30..60  ...) AS d30_60,
       SUM(... 60..90  ...) AS d60_90,
       SUM(... 90..120 ...) AS d90_120,
       SUM(... 120+    ...) AS d120_plus
  FROM ClaimRecord
 WHERE status NOT IN ('paid', 'written_off')
 GROUP BY payer_id

What's wired

| Entity | Purpose | |---|---| | PayerContract | Timely-filing window, appeal window, network status | | FeeScheduleEntry | Contracted allowed amount per payer × CPT × modifier | | ClaimRecord | Full claim lifecycle, billed/paid/written-off math | | ClaimLine | Line-level CPT / modifier / diagnosis detail | | DenialRecord | Every denial with group code, reason code, routed action |

Tools (11): list_payer_contracts, create_payer_contract, list_fee_schedule, set_fee_schedule_entry, list_claims, create_claim, add_claim_line, submit_claim, post_denial, list_denials, ar_aging_by_payer.


What's coming (slice C and beyond)

The deterministic spine ships first. The AI-rule loop builds on top of it.