Cross-Engine Data Reconciliation Architecture › Discrepancy Routing and Remediation

Discrepancy Routing and Remediation

Discrepancy routing and remediation is the stage where reconciliation stops observing and starts acting: the workload that takes a delta manifest and decides, per discrepancy, whether to auto-correct it, quarantine it for later, or escalate it to a human. This reference sits inside the cross-engine data reconciliation architecture and is the last mile of the control plane — the point at which a detected divergence becomes a resolved one. It is written for the data engineers, migration specialists, Python pipeline builders, and platform operations teams who must ensure that finding a discrepancy actually leads to fixing it, without a well-meaning auto-remediation making things worse.

The stage exists because not every discrepancy is equal, and treating them uniformly fails in both directions. Auto-correcting everything risks a remediation loop that overwrites good data with bad; escalating everything buries a real incident under noise a human cannot triage. The discipline is severity-aware routing: classify each discrepancy by how confident and how consequential it is, send the safe and confident ones to idempotent auto-resync, the uncertain ones to a dead-letter queue for deferred handling, and the consequential ones to human review — every action recorded for audit.

Severity-based routing of manifest discrepancies to remediation paths A delta manifest feeds a classifier that scores each discrepancy by confidence and consequence. The classifier routes to three paths: high-confidence low-consequence records go to idempotent auto-resync, uncertain records go to a dead-letter queue for deferred handling, and high-consequence records go to human review. All three paths write to an append-only audit store. confident · safe uncertain consequential Delta manifest discrepancies Classifier confidence × consequence Idempotent auto-resync safe corrections Dead-letter queue deferred handling Human review escalation Append-only audit every action logged
The classifier scores each discrepancy by confidence and consequence and routes it to auto-resync, dead-letter, or human review — and every path writes to an append-only audit store.

Architectural Boundaries

This workload consumes the serialized delta manifest and produces routed, acted-upon outcomes plus an audit record per discrepancy. It owns the routing decision and the remediation action; it does not decide what counts as a discrepancy (the comparison and tolerance stages do) nor how the manifest is produced. The boundary keeps remediation from silently re-defining parity: routing acts on the verdicts it is given, and any disagreement with those verdicts is a bug in the classifier’s policy, not a quiet correction.

Prerequisites

Step-by-Step Implementation

1. Classify by confidence and consequence

Routing turns on two axes: how sure the pipeline is that the discrepancy is real and correctable, and how much damage a wrong correction would do. The classifier is a pure function of the discrepancy and policy, so it is testable and reproducible.

python
import logging
from dataclasses import dataclass
from enum import Enum

logging.basicConfig(
    format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", level=logging.INFO
)
logger = logging.getLogger("recon.arch.routing")


class Route(Enum):
    AUTO_RESYNC = "auto_resync"
    DEAD_LETTER = "dead_letter"
    HUMAN_REVIEW = "human_review"


@dataclass(frozen=True)
class Discrepancy:
    id: str
    category: str            # e.g. "missing_in_target", "value_diverged"
    confidence: float        # 0..1, how sure the verdict is
    consequence: str         # "low", "high" (e.g. money/PII)


def classify(d: Discrepancy) -> Route:
    """Route by confidence and consequence; consequential cases always see a human."""
    if d.consequence == "high":
        return Route.HUMAN_REVIEW
    if d.confidence >= 0.95:
        return Route.AUTO_RESYNC
    return Route.DEAD_LETTER

2. Remediate idempotently

An auto-resync applies the source-of-truth value to the target keyed on the discrepancy id, so a retry or a replay is a no-op. It never runs for a high-consequence discrepancy.

python
@dataclass
class Remediator:
    apply_correction: callable      # (discrepancy_id, correction) -> None, idempotent
    _done: set = None

    def __post_init__(self):
        self._done = set()

    def resync(self, d: Discrepancy, correction: dict) -> bool:
        if d.id in self._done:
            logger.info("remediation already applied id=%s", d.id)
            return False
        self.apply_correction(d.id, correction)   # keyed on id -> idempotent at the sink
        self._done.add(d.id)
        logger.info("auto-resync applied id=%s", d.id)
        return True

3. Route, act, and audit

Every discrepancy flows through classification to its path, and every action — including a decision to defer or escalate — is recorded before control returns.

python
def route_and_record(d: Discrepancy, remediator: Remediator, audit: callable, get_correction) -> Route:
    route = classify(d)
    if route is Route.AUTO_RESYNC:
        remediator.resync(d, get_correction(d.id))
    audit({"id": d.id, "route": route.value, "category": d.category})
    return route

Routing Policy Trade-Off

The aggressiveness of auto-remediation is a deliberate risk choice.

Policy Speed to resolve Risk of wrong correction Human load Compliance / regulatory
Auto-resync everything confident Fastest Higher; a bad verdict propagates Lowest Weak for regulated data; a wrong write is hard to defend.
Confidence + consequence gating (this page) Fast for safe cases Low; consequential cases escalate Moderate Strong: high-consequence data always sees a human.
Dead-letter then batch review Slower Lowest Higher Strongest: nothing auto-writes; every change is reviewed.
Escalate everything Slowest None from automation Highest Strong but unscalable; buries real incidents in noise.

Scaling and Performance

Classification is O(discrepancies) and stateless, so it parallelises trivially; the constraint is the remediation sink’s write capacity and the human-review channel’s throughput, neither of which scales like compute. Rate-limit auto-resync so a large manifest cannot storm the target, and batch dead-letter writes so a spike of uncertain discrepancies does not overwhelm the queue. Keep the loop guard’s seen-set bounded with a TTL keyed on the reconciliation interval so a re-appearing discrepancy is caught without the guard growing without limit. Shard routing by key range for very large manifests, and prioritise high-consequence discrepancies to the front of the review channel so the most important cases are triaged first regardless of manifest order.

Failure Modes and Diagnostic Runbook

  • Remediation loop. Cause: an auto-resync that does not actually fix the divergence, so the discrepancy reappears each run. Detection signal: the same discrepancy id recurs across consecutive runs. Remediation: the loop guard routes a re-appearing id to human review; fix the root cause before re-enabling auto-resync.
  • Escalation overload. Cause: the consequence threshold is set too broad, sending routine cases to humans. Detection signal: review queue depth grows unbounded. Remediation: tighten the consequence policy; move confidently-safe categories back to auto-resync.
  • Dead-letter black hole. Cause: deferred discrepancies are enqueued but never processed. Detection signal: dead-letter depth rises monotonically. Remediation: follow routing discrepancies to dead-letter queues for reprocessing SLAs and alerting.
  • Unaudited correction. Cause: a remediation path that acts before writing its audit record. Detection signal: data changed with no matching audit entry. Remediation: make the audit write a precondition of the action, never a follow-up.

Deep Dives