Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt

Use this file to discover all available pages before exploring further.

Spec: PM-29
Status: 📝 Planned
Last Updated: 2026-03-02
Owner: PM Core

Overview

PM-29 introduces the denial management and appeals workflow. It integrates with multiple PM specs (claim status, ERA, prior auth, analytics, scrubbing), PF-29 (tasks), and PF-70 (code library). All integrations are within the PM core or via the Platform Integration Layer; no direct cross-core imports.

Integration Points

PM-08 — Claims Management & Submission

Pattern: Data (same core)
Direction: PM-29 → PM-08 (reads claim data; triggers resubmission)
InteractionDetails
Claim status update on appeal outcomeWhen appeal status transitions to won or lost, PM-29 updates pm_claims.status via internal hook; no cross-core import needed (same PM core)
Bulk re-submit triggerBulk re-submit action calls PM-08 resubmission function; batch size governed by org PM-28 setting (default 100, max 500)
Claim data readDenial queue reads pm_claims (claim_number, payer, provider, dates) for display and merge fields
Contract: Internal same-core data access. No event contract needed.

PM-09 — Payment Posting & ERA Processing

Pattern: Data (same core)
Direction: PM-09 → PM-29 (denial intake from ERA)
InteractionDetails
ERA denial auto-intakeDuring ERA posting, PM-09 auto-creates pm_claim_denials rows for all CO/PR/OA adjustment reason codes. Fields populated: claim_id, denial_reason_code, denial_category (mapped from CARC), denial_date, amount_denied, payer_appeal_deadline (calculated), remittance_id
CARC/RARC mappingPM-09 maps CARC/RARC codes to denial_category enum (auth, eligibility, coding, medical_necessity, other) during ERA processing
Contract: Internal same-core function call. pm_claim_denials insert triggered by PM-09 ERA posting logic.

PM-10 — Prior Authorization Management

Pattern: Data (same core)
Direction: PM-29 reads PM-10 data for auth-denial linking
InteractionDetails
Auth denial linkWhen denial_category = 'auth' and ERA REF segment contains authorization reference, PM-09 populates prior_authorization_id FK on pm_claim_denials pointing to pm_prior_authorizations.id
Appeal contextAppeal workflow may surface prior auth details (auth number, expiration, requested units) from pm_prior_authorizations for inclusion in appeal letter merge fields
Contract: Internal same-core FK read. No event contract needed.

PM-11 — Revenue Cycle Dashboard & Analytics

Pattern: Data / Platform Layer (same core)
Direction: PM-29 → PM-11 (denial metrics feed)
InteractionDetails
First-pass acceptance ratePM-11 KPI widget reads from pm_claim_denials to compute: (adjudicated_paid_without_denial ÷ total_adjudicated) × 100
Denial rate by payer/reason/provider/service typePM-11 analytics pull aggregated denial data from pm_claim_denials grouped by payer, denial_category, assigned provider, service date
Dashboard linkPM-11 RCM dashboard widgets link to /pm/denials pre-filtered by dimension
Contract: Internal same-core data reads. Queries defined in PM-29 analytics hooks; consumed by PM-11 dashboard.

PM-18 — Configurable Claim Scrubbing (Phase 2)

Pattern: Data (same core) — Deferred to Phase 2
Direction: PM-29 → PM-18 (denial pattern → scrub rule suggestions)
InteractionDetails
Denial-driven rule suggestionsPhase 2: PM-18 rule-suggestion engine reads denial history from pm_claim_denials to surface patterns (e.g. “47 denials for missing auth from Payer X → suggest adding auth-required scrub rule”)
Status: Deferred to Phase 2. No contract defined at PM-29 MVP. See specs/DEFERRED_DASHBOARD.md for tracking.

PF-29 — Tasks

Pattern: Platform Layer
Direction: PM-29 → PF-29 (auto-creates follow-up task on appeal submission)
Status: ✅ Contract resolved — PF-29 is Complete; @/platform/tasks TaskInsert type is canonical.
InteractionDetails
Auto-task on appeal submitWhen pm_appeal_submissions is inserted with status = 'submitted', PM-29 calls useTaskMutation().create() from @/platform/tasks
Manual task creationDenial detail view renders <TaskFormDialog> from @/platform/tasks; pre-populated with denial context
Phase 2: deadline alertsCron-triggered follow-up N days before deadline (deferred — see DEFERRED_DASHBOARD.md)
Payload (auto-task on appeal submit):
import { useTaskMutation } from '@/platform/tasks';

// Called from PM-29 appeal submit handler
const { create } = useTaskMutation();

create({
  organization_id: organizationId,
  title: `Follow up: appeal for claim ${claimNumber}`,
  description: `Appeal submitted for denial on ${denialDate}. Payer: ${payerName}. Category: ${denialCategory}.`,
  status: 'open',
  priority: 'high',             // Overdue risk: missed deadline = lost revenue
  assigned_to: assignedTo,      // Defaults to current user; reassignable
  due_date: payerAppealDeadline, // DATE string from pm_claim_denials.payer_appeal_deadline
  source_type: 'pm_appeal',     // PM-29 source type; extend TaskSourceType union
  source_id: appealSubmissionId, // pm_appeal_submissions.id
  custom_fields: {
    denial_id: denialId,
    claim_id: claimId,
    denial_category: denialCategory,
  },
});
source_type registration: Add 'pm_appeal' to the TaskSourceType union in src/platform/tasks/types.ts. This extends the existing string open union; add it as a named literal for type safety and filtering. due_date conversion note: payer_appeal_deadline is stored as TIMESTAMPTZ. Convert to DATE string (YYYY-MM-DD in org timezone) before passing to due_date: DATE on pf_tasks. Use formatInUserTimeZone(deadline, 'yyyy-MM-dd') from @/platform/forms.

PF-70 — Medical Terminology Code Libraries

Pattern: Platform Layer
Direction: PM-29 reads PF-70 for CARC/RARC code descriptions
InteractionDetails
CARC/RARC description lookupDenial reason code display resolves CARC/RARC descriptions from PF-70 when available. Fallback: local seeded lookup table in PM-29 migrations (CMS-published static list)
Fallback strategyPM-29 migrations include seed for CMS CARC/RARC codes. Replace with PF-70 query when CARC/RARC is confirmed in PF-70 scope
Contract: Read-only platform layer query. See PF-70 Integration.

Platform Layer Usage

LayerUsed ByPurpose
@/platform/tasks (PF-29)PM-29 appeal submissionAuto-create follow-up task
@/platform/permissions (PF-30)PM-29 UIPermission-gate denial queue, appeal creation
@/platform/table-v2PM-29 denial queueDataTable with sort/filter/virtual scroll
@/platform/formsPM-29 denial entry, appeal formForm management
Sonner (toast)PM-29 actionsBulk assign, submit, status update toasts

Events

PM-29 does not publish events at MVP. Potential future events (Phase 2+):
EventPublisherConsumersStatus
pm_denial_createdPM-29PM-18 (rule suggestions)Deferred Phase 2
pm_appeal_submittedPM-29PF-10 (deadline notification)Deferred Phase 2
pm_appeal_outcome_recordedPM-29PM-11 (KPI refresh), PM-08 (claim status)Deferred Phase 2

Security & Tenancy

  • All tables RLS-protected with pm_has_org_access(organization_id, auth.uid()).
  • No PHI in logs or event payloads.
  • Permission keys: pm.denials.view, pm.denials.manage, pm.appeals.submit.
  • Template letter HTML: merge fields HTML-escaped before insertion (XSS prevention).

Pending Contracts

ItemBlocking OnStatusNotes
PF-29 task creation payload schemaPF-29 task creation API contract✅ Resolved 2026-03-02PF-29 is Complete; useTaskMutation().create() from @/platform/tasks; source_type: 'pm_appeal'; add to TaskSourceType union in src/platform/tasks/types.ts. Full payload in PF-29 section above.
PM-18 Phase 2 denial-pattern feedPM-18 Phase 2 implementation⏳ DeferredDenial history query design and suggestion-surface API TBD when PM-18 Phase 2 is scheduled. Tracked in DEFERRED_DASHBOARD.md.