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-49
Created: 2026-04-07
Status: 📝 Planned
Overview
PM-49 provides a configurable rules engine for automating routine revenue cycle decisions with pre-built behavioral health rule templates. It builds on PM-19’s general business rule automation framework with RCM-specific templates, actions, and work queue prioritization.
| PF Feature | Integration Type | Usage |
|---|
| PF-01 (Organizations & Sites) | Direct dependency | Organization and site context for rules and queue scoping |
| PF-02 (RBAC) | Direct dependency | Permission checks: pm.rcm-rules.*, pm.rcm-queue.*, pm.rcm-log.* |
| PF-10 (Notifications) | Platform Integration Layer | Alert billing managers on circuit breaker trips, batch completions, rule failures |
| PF-29 (Tasks) | Platform Integration Layer | Create tasks from rule actions (e.g., manual review needed) |
| PF-96 (Jurisdiction Profiles) | Platform Integration Layer | Filing deadline resolution for automated resubmissions |
Internal PM Dependencies
| PM Feature | Integration Pattern | Usage |
|---|
| PM-19 (Business Rule Automation) | Extends | PM-49 extends PM-19’s rule framework with RCM-specific templates, actions, and execution patterns |
| PM-29 (Denial Management) | API/Event | PM-49 triggers denial re-submissions through PM-29 workflows when denial rules match (see API contracts) |
| PM-09 (Payment Posting) | Event (consumed) / API | PM-49 posts adjustments through PM-09 posting hooks; consumes pm_era_posted, pm_payment_posted events (see API contracts) |
| PM-45 (Collections) | API | PM-49 transfers accounts to PM-45 collections tiers based on aging rules (see API contracts) |
| PM-11 (Revenue Cycle Dashboard) | Event (published) | PM-49 publishes pm_rcm_rule_executed for PM-11 dashboard metrics |
API Contracts
Full contract details: See API_CONTRACTS.md
PM-49 → PM-09 (Payment Posting)
Purpose: Auto-post small balance adjustments and contractual adjustments
Endpoint pattern: Edge function or SECURITY DEFINER RPC
Request Schema:
{
organization_id: string; // UUID
claim_id: string; // UUID
adjustment_code: string; // e.g., "SB-WRITEOFF", "CONTR-ADJ"
adjustment_amount: number; // Decimal
reason_text: string; // Human-readable reason
rule_execution_id?: string; // UUID (for audit trail)
}
Response Schema:
{
success: boolean;
adjustment_id?: string; // UUID if success
error_code?: string; // e.g., "CLAIM_NOT_FOUND", "INSUFFICIENT_BALANCE"
error_message?: string;
}
Error Codes:
CLAIM_NOT_FOUND: Claim ID does not exist
INSUFFICIENT_BALANCE: Balance lower than adjustment amount
INVALID_ADJUSTMENT_CODE: Unrecognized code
ORG_MISMATCH: Claim does not belong to organization
Idempotency: Use rule_execution_id as idempotency key; duplicate requests return existing adjustment_id
PM-49 → PM-29 (Denial Management)
Purpose: Auto-trigger denial re-submissions for correctable denial codes
Endpoint pattern: Edge function or SECURITY DEFINER RPC
Request Schema:
{
organization_id: string; // UUID
denial_id: string; // UUID
resubmission_reason: string; // e.g., "auto-resubmit CO-4 modifier"
correction_notes?: string; // Optional correction instructions
rule_execution_id?: string; // UUID (for audit trail)
}
Response Schema:
{
success: boolean;
resubmission_id?: string; // UUID if success
error_code?: string; // e.g., "DENIAL_NOT_FOUND", "FILING_DEADLINE_PASSED"
error_message?: string;
}
Error Codes:
DENIAL_NOT_FOUND: Denial ID does not exist
FILING_DEADLINE_PASSED: Resubmission past filing deadline (resolved via PF-96)
ALREADY_RESUBMITTED: Denial already has pending resubmission
ORG_MISMATCH: Denial does not belong to organization
Idempotency: Use rule_execution_id as idempotency key
Filing Deadline Resolution: Uses PF-96 jurisdiction profile to validate resubmission window (see PF-96 API contracts)
PM-49 → PM-45 (Collections)
Purpose: Auto-transfer accounts to collections tiers based on aging rules
Endpoint pattern: Edge function or SECURITY DEFINER RPC
Request Schema:
{
organization_id: string; // UUID
account_id: string; // UUID or claim_id
collections_tier: string; // e.g., "early", "standard", "final"
transfer_reason: string; // Human-readable reason
rule_execution_id?: string; // UUID (for audit trail)
}
Response Schema:
{
success: boolean;
collections_entry_id?: string; // UUID if success
error_code?: string; // e.g., "ACCOUNT_NOT_FOUND", "ALREADY_IN_COLLECTIONS"
error_message?: string;
}
Error Codes:
ACCOUNT_NOT_FOUND: Account/claim ID does not exist
ALREADY_IN_COLLECTIONS: Account already assigned to collections tier
INELIGIBLE_PAYER: Payer type excluded from collections (e.g., Medicaid in some states)
ORG_MISMATCH: Account does not belong to organization
Idempotency: Use rule_execution_id as idempotency key
Event Contracts
Events Consumed
| Event | Source | Purpose |
|---|
pm_era_posted | PM-09 | Triggers event-based rules for auto-posting contractual adjustments |
pm_denial_received | PM-29 | Triggers denial re-submission rules |
pm_payment_posted | PM-09 | Triggers zero-balance close rules |
Events Published
| Event | Subscribers | Payload Schema |
|---|
pm_rcm_rule_executed | PM-11 | { rule_id: string; rule_type: string; action_taken: string; target_entity_id: string; dollar_amount?: number; organization_id: string; } |
Scheduled Processing
| Job Name | Schedule | Edge Function | Purpose |
|---|
pm-rcm-rule-batch | Hourly dispatcher (tenant-timezone aware) | rcm-execute-rules | Nightly batch rule evaluation (target: 2 AM org/site local time) |
pm-rcm-queue-scoring | Hourly dispatcher (tenant-timezone aware) | rcm-score-work-queue | Nightly work queue re-scoring (target: 3 AM org/site local time) |
Tenant-Timezone Execution Strategy:
Both pm-rcm-rule-batch and pm-rcm-queue-scoring use a dispatcher pattern to execute at tenant-local time (2 AM and 3 AM respectively):
- Fixed hourly cron:
0 * * * * — runs every hour
- Dispatcher logic:
- For each organization, resolve effective timezone (site timezone if available, otherwise org default)
- Calculate current local time in that timezone
- If local time matches target hour (02:00 for rules, 03:00 for scoring), enqueue/execute for that organization
- Skip organizations already processed in current day window
- Job targets:
pm-rcm-rule-batch invokes rcm-execute-rules with organization_id when tenant-local time is 02:00
pm-rcm-queue-scoring invokes rcm-score-work-queue with organization_id when tenant-local time is 03:00
- Metadata: Batch execution persists timezone used for audit reproducibility (see spec §Scope clarification table)
Alternative: Per-tenant scheduled jobs can be configured if the dispatcher approach does not meet scaling requirements.
Security Considerations
- All tables enforce organization-scoped RLS
- Execution records are immutable (no UPDATE/DELETE policies)
- Rule activation requires segregation of duties (creator != activator, except Director override)
- No PHI in rule definitions — rules reference account properties only
- Jurisdiction-aware filing deadlines via PF-96
Validation Checklist
Last Updated: 2026-04-07