Deadline Tracking Routing Engines

Routing Compliance Tasks to Regional Legal-Ops Teams

This guide is part of the Registered Agent Assignment Logic area within the Deadline Tracking & Routing Engines framework: it drills into one sub-problem of assignment — given a stream of already-validated filing tasks, deciding which regional legal-ops team owns each one and delivering it to that team’s queue without ever stranding a statutory deadline.

Scope of This Page

This page covers the routing layer only: how to map a task’s jurisdiction onto an owning regional queue, how to fall back deterministically when the primary queue is saturated or unreachable, and how to record every routing decision in an append-only audit trail. It deliberately excludes adjacent machinery documented elsewhere — obligation scoring and admission ordering, the concurrency model for dispatching to portals, the schema validation that admits a task in the first place, and the agent-of-record assignment itself. We assume each incoming task is single-intent, schema-valid, and already carries its jurisdiction code; here we decide who works it and prove where it went.

The Constraint That Forces Regional Routing

Regional routing is not an org-chart nicety — it is driven by where work may lawfully and practically be performed. Statements of Information filed under Cal. Corp. Code § 1502 and Delaware franchise-tax filings under Del. Code Ann. tit. 8, § 502 carry distinct deadlines, portal hours, and escalation paths, and the legal-ops staff who hold portal credentials and case knowledge for each registry are organized by region. A task routed to the wrong team is not merely inefficient: it can miss a same-day Delaware settlement window or a New York biennial cutoff (N.Y. Bus. Corp. Law § 408) while it waits in a queue nobody who can act is watching. Routing therefore has to be deterministic (the same task always reaches the same owner), idempotent (a retried route never double-enqueues), and auditable (every assignment is provable after the fact for reconciliation).

Prerequisites

  • Python 3.10+ — for X | Y unions, match statements, and modern asyncio.
  • Standard library only: asyncio, dataclasses, enum, hashlib, json, logging, time.
  • A queue client per region (SQS, Redis Streams, RabbitMQ, or an internal task bus) exposing an async push(queue, task) and a depth(queue) health probe.
  • A routing table mapping jurisdiction codes to a primary region and an ordered fallback chain, kept as configuration data — not branches in code.
  • An append-only audit sink (write-once table or immutable-retention log stream) for routing decisions.
  • A stream of pre-validated, single-intent task records carrying entity_id, jurisdiction, and statutory_deadline (see the parent Registered Agent Assignment Logic task model).

Implementation: A Deterministic Regional Router

The module below resolves each task to its owning region from a configuration table, probes that region’s queue depth before committing, and walks an ordered fallback chain when the primary is saturated or unreachable. Every route is keyed by a stable routing_hash so a retried task lands on the same queue rather than fanning out, and every decision is hashed into a tamper-evident audit record. Comments mark the compliance-critical lines.

One compliance task through the deterministic regional router A validated task gets a stable routing_hash, resolves a primary region from the jurisdiction table, and probes queue depth. Under ceiling: push to the regional queue and seal ROUTED. At or over ceiling or on push error: advance to the next fallback region and re-probe. Chain exhausted: seal ESCALATED and place on the human review queue. ComplianceTask in validated · single-intent · carries jurisdiction compute routing_hash stable idempotency key · SHA-256 over id+deadline resolve primary region jurisdiction routing table · config, not branches probe queue depth vs region ceiling push to regional queue primary or fallback · within 5s budget ROUTED sealed audit record → audit sink advance to next fallback region declared order · looser ceiling (2×) ESCALATED sealed audit record → audit sink Human review queue officer files before statutory cutoff depth < ceiling ≥ ceiling · push error retry next region chain exhausted
from __future__ import annotations

import asyncio
import hashlib
import json
import logging
import time
from dataclasses import dataclass, field
from enum import Enum
from typing import AsyncGenerator, Optional, Protocol

# Structured JSON logging — every line is a parseable audit/observability event.
logging.basicConfig(level=logging.INFO, format="%(message)s")
logger = logging.getLogger("routing.regional_dispatch")


class RouteStatus(Enum):
    ROUTED = "routed"          # placed on a regional queue (primary or fallback)
    ESCALATED = "escalated"    # fallback chain exhausted — sent to human review


class QueueClient(Protocol):
    async def push(self, queue: str, task: "ComplianceTask") -> None: ...
    async def depth(self, queue: str) -> int: ...


@dataclass(frozen=True)
class RegionRoute:
    jurisdiction: str          # e.g. "US-DE"
    primary: str               # owning regional queue
    fallbacks: tuple[str, ...] # ordered chain tried when primary is unavailable
    depth_ceiling: int         # backpressure threshold for the primary queue


@dataclass
class ComplianceTask:
    entity_id: str
    jurisdiction: str
    statutory_deadline: float          # Unix timestamp
    routing_hash: str = ""
    assigned_queue: Optional[str] = None
    fallback_depth: int = 0

    def __post_init__(self) -> None:
        # Stable hash over identity + deadline: the same task always routes the
        # same way, so a retry is idempotent rather than a second enqueue.
        if not self.routing_hash:
            payload = f"{self.entity_id}:{self.jurisdiction}:{self.statutory_deadline}"
            self.routing_hash = hashlib.sha256(payload.encode("utf-8")).hexdigest()[:16]


@dataclass(frozen=True)
class RoutingRecord:
    routing_hash: str
    entity_id: str
    jurisdiction: str
    status: RouteStatus
    queue: str
    fallback_depth: int
    timestamp: float
    integrity_hash: str = field(default="")

    def sealed(self) -> "RoutingRecord":
        # Tamper-evident seal over everything but the seal field itself.
        body = {k: v for k, v in self.__dict__.items() if k != "integrity_hash"}
        body["status"] = self.status.value
        canonical = json.dumps(body, sort_keys=True, separators=(",", ":"))
        digest = hashlib.sha256(canonical.encode("utf-8")).hexdigest()
        return RoutingRecord(**{**body, "status": self.status, "integrity_hash": digest})


class RegionalRouter:
    ESCALATION_QUEUE = "global-compliance-escalation"

    def __init__(self, table: dict[str, RegionRoute], client: QueueClient) -> None:
        self.table = table
        self.client = client

    async def _try_queue(self, queue: str, ceiling: int, task: ComplianceTask) -> bool:
        # Probe backpressure before committing: a saturated queue would silently
        # delay a statutory deadline, so we treat it as unavailable and fall back.
        try:
            if await self.client.depth(queue) >= ceiling:
                return False
            await asyncio.wait_for(self.client.push(queue, task), timeout=5.0)
            return True
        except (asyncio.TimeoutError, ConnectionError) as exc:
            logger.warning(json.dumps({"event": "queue_unavailable", "queue": queue,
                                       "entity_id": task.entity_id, "error": str(exc)}))
            return False

    async def route(self, task: ComplianceTask) -> RoutingRecord:
        route = self.table.get(task.jurisdiction)
        if route is None:  # unknown jurisdiction is a data defect, not a routing target
            return self._seal(task, RouteStatus.ESCALATED, self.ESCALATION_QUEUE)

        # Primary first, then each fallback in declared order — deterministic chain.
        candidates = (route.primary, *route.fallbacks)
        for depth, queue in enumerate(candidates):
            ceiling = route.depth_ceiling if depth == 0 else route.depth_ceiling * 2
            if await self._try_queue(queue, ceiling, task):
                task.assigned_queue, task.fallback_depth = queue, depth
                return self._seal(task, RouteStatus.ROUTED, queue)

        # Chain exhausted: never drop a deadline — hand to supervised escalation.
        await self.client.push(self.ESCALATION_QUEUE, task)
        task.fallback_depth = len(candidates)
        return self._seal(task, RouteStatus.ESCALATED, self.ESCALATION_QUEUE)

    def _seal(self, task: ComplianceTask, status: RouteStatus, queue: str) -> RoutingRecord:
        record = RoutingRecord(task.routing_hash, task.entity_id, task.jurisdiction,
                               status, queue, task.fallback_depth, time.time()).sealed()
        logger.info(json.dumps({
            "level": "WARNING" if status is RouteStatus.ESCALATED else "INFO",
            "event": "task_routed", "routing_hash": record.routing_hash,
            "entity_id": record.entity_id, "jurisdiction": record.jurisdiction,
            "status": record.status.value, "queue": record.queue,
            "fallback_depth": record.fallback_depth, "seal": record.integrity_hash,
        }))
        return record

    async def run(self, source: AsyncGenerator[ComplianceTask, None]) -> list[RoutingRecord]:
        return [await self.route(task) async for task in source]

The router is deliberately a leaf: it makes no priority decisions and performs no portal submission. It consumes single-intent tasks and returns one sealed RoutingRecord per task — routed or escalated — leaving execution to the owning regional team and reconciliation to the surrounding engine.

Configuration Reference

Routing targets, ceilings, and fallback order are configuration data, never branches in the routing loop, because they are dictated by team coverage and registry behavior rather than by your code.

Parameter Suggested value Legal / operational justification
primary (US-DE) us-east-legal-ops Delaware’s same-day settlement window (§ 502) demands a team in a timezone that can act before cutoff.
primary (US-CA) us-west-legal-ops BizFile § 1502 work runs in California business hours (08:00–17:00 PT); route to staff in that window.
primary (US-NY) us-east-legal-ops NY biennial filings (§ 408) share East-coast coverage and escalation paths with Delaware.
primary (US-TX) us-central-legal-ops Texas Comptroller May 15 Public Information Reports are owned by the central region.
depth_ceiling 250 Backpressure threshold per regional queue; above it, fall back rather than let a deadline wait.
Fallback ceiling multiplier 2x Fallback queues absorb overflow at a looser ceiling so the chain does not escalate prematurely.
push timeout 5s Fails fast on an unreachable queue so the next fallback is tried within the deadline budget.
routing_hash length 16 hex Stable idempotency key per task; collisions are negligible at portfolio scale and keep logs compact.

Failure Modes and Fallback Routing

The router maps each fault onto the four-tier scheme defined in the portal area’s error categorization & retry logic — transient, statutory, data-validation, and system — and responds to each differently.

  1. Primary queue saturated (transient/backpressure). depth() reports the queue at or above its ceiling. This is a pacing signal, not a failure: the router advances to the next region in the declared chain at a looser ceiling. It never blocks on the saturated queue, because a waiting Delaware task can miss its settlement window.
  2. Queue push timeout or connection error (system). The broker is unreachable inside the 5-second budget. The router logs queue_unavailable, treats the target as unavailable, and falls back. A region that returns sustained failures should be circuit-broken upstream so the chain stops re-probing a dead broker.
  3. Unknown jurisdiction code (data-validation). No routing-table entry exists for the task’s jurisdiction. This is a data defect, not a routing target: the task is sealed ESCALATED to the global review queue rather than guessed onto a regional team, and the upstream classifier is alerted to the bad code.
  4. Fallback chain exhausted (statutory/escalation). Every candidate region is saturated or unreachable. The task is pushed to the supervised escalation queue with its routing_hash and deadline intact, so a compliance officer can place it manually before the statutory cutoff. Nothing is ever silently dropped, and the idempotent hash means a later automated retry cannot double-enqueue it.

Frequently Asked Questions

Why probe queue depth before routing instead of just pushing to the primary?

Because a push that succeeds onto a saturated queue is the worst outcome: the task is “delivered” but sits behind hundreds of others while its statutory deadline elapses, and no error ever fires. Probing depth() against a per-region ceiling lets the router treat a backed-up queue as unavailable and fall back to a region with capacity, so a deadline is bounded by processing availability, not just delivery success.

What stops a retried task from being routed to two different teams?

The stable routing_hash, derived from the entity ID, jurisdiction, and statutory deadline and never regenerated. The router resolves the same candidate chain in the same order for an identical hash, and the regional queue client uses the hash as a dedup key, so a replayed task collapses onto the existing assignment rather than fanning out to a second team.

How is regional ownership kept correct when a deadline crosses timezones?

Ownership follows the registry, not the calendar: the routing table binds each jurisdiction to the region whose business hours overlap that portal’s filing window. A Delaware task always routes to the East-coast team regardless of where the portfolio’s headquarters sits, because that team holds the credentials and can act inside the § 502 settlement window. The table is the single source of truth, so a coverage change is a one-line config edit, not a code change.

What happens to a task whose jurisdiction has no routing-table entry?

It is never guessed onto a regional team. The router seals it ESCALATED to the global review queue and emits a WARNING-level structured log so the upstream classifier can be corrected. Routing to a plausible-but-wrong region would hide a data defect behind an apparently successful assignment, which is exactly the failure regional routing exists to prevent.