Katkat

Debug a Stale Insurance Eligibility Status

HeadwaySoftware Engineer · Onsite

Last updated

Tests your ability to resolve data staleness and synchronization bugs between denormalized cache records and immutable event snapshots, while establishing clear domain invariants and handling out-of-order writes.

Scenario

In a healthcare platform, provider dashboards display a patient's insurance verification status. To optimize read latency on high-volume patient roster queries, UserInsurance denormalizes and caches eligibility_status and last_verified_at. Meanwhile, automated cron jobs and third-party clearinghouse webhooks write timestamped verification audit records to an append-only EligibilityLookup table.

Under concurrent checks and asynchronous webhook deliveries, providers frequently observe stale or incorrect eligibility statuses on the dashboard (e.g., an older INACTIVE response arriving late overwrites a newer ACTIVE check, or a lookup fails and clobbers a previously valid verification).

Requirements

Design and implement an EligibilityReconciler service that reliably maintains data consistency between snapshots and cached state.

Data Models

from dataclasses import dataclass
from datetime import datetime
from enum import Enum
from typing import Optional

class Status(str, Enum):
    ACTIVE = "ACTIVE"
    INACTIVE = "INACTIVE"
    PENDING = "PENDING"
    ERROR = "ERROR"

@dataclass
class EligibilityLookup:
    id: str
    user_insurance_id: str
    status: Status
    checked_at: datetime
    error_code: Optional[str] = None

@dataclass
class UserInsurance:
    id: str
    patient_id: str
    cached_status: Status
    last_verified_at: Optional[datetime]
    version: int = 0

Task

Implement the following class:

class EligibilityReconciler:
    def record_lookup(
        self,
        user_insurance: UserInsurance,
        lookup: EligibilityLookup,
    ) -> UserInsurance:
        """
        Applies a new lookup snapshot to the UserInsurance entity.
        Updates cached_status and last_verified_at strictly if the lookup
        satisfies state reconciliation invariants. Returns the updated UserInsurance.
        """
        pass

    def reconcile_from_history(
        self,
        user_insurance: UserInsurance,
        lookups: list[EligibilityLookup],
    ) -> UserInsurance:
        """
        Recomputes the canonical status from a complete history of snapshots,
        resolving any out-of-order or corrupt cached state.
        """
        pass

Invariants & Business Rules

  1. Monotonic Timestamps: A lookup must never regress last_verified_at. An incoming lookup with checked_at strictly older than last_verified_at must not overwrite cached_status.
  2. Transient Errors: Lookups with status == Status.ERROR represent third-party communication failures. An ERROR snapshot must never overwrite an existing ACTIVE or INACTIVE state. However, if the insurance has never been verified (i.e., last_verified_at is None), an initial ERROR should set cached_status to ERROR.
  3. Deterministic Tie-Breaking: If two lookups have identical checked_at timestamps, ACTIVE takes precedence over INACTIVE, and both take precedence over PENDING.
  4. Version Increment: Every state update to UserInsurance must increment version by 1. If an incoming lookup causes no change to cached values, version remains unchanged.

Example

t0 = datetime(2025, 1, 1, 10, 0, 0)
t1 = datetime(2025, 1, 1, 10, 5, 0)

insurance = UserInsurance(
    id="ins_1",
    patient_id="pat_1",
    cached_status=Status.ACTIVE,
    last_verified_at=t1,
    version=1
)

# Stale out-of-order lookup arrives from an earlier batch check
stale_lookup = EligibilityLookup(
    id="chk_old",
    user_insurance_id="ins_1",
    status=Status.INACTIVE,
    checked_at=t0
)

reconciler = EligibilityReconciler()
result = reconciler.record_lookup(insurance, stale_lookup)
assert result.cached_status == Status.ACTIVE
assert result.last_verified_at == t1
assert result.version == 1  # No state update

Hints

Hint 1

Identify which statuses represent conclusive verification results versus transient network failures before deciding if a timestamp comparison is even relevant.

Hint 2

For history reconciliation, sort lookups by verification timestamp and apply deterministic tie-breaking rules before folding them into the final cached state.

Hint 3

Consider optimistic concurrency control (e.g., checking `version` or conditional writes in the database) to prevent race conditions during concurrent write operations.

Follow-up questions

  • How would you handle concurrent writes to the same `UserInsurance` row in PostgreSQL without introducing lock contention on patient list reads?
  • If business requirements mandate expiring active statuses after 30 days without an active lookup, how would you design this without scanning millions of rows on read?
  • What metrics, alerts, and reconciliation batch jobs would you implement to detect drift between `EligibilityLookup` events and `UserInsurance` cached state?