Deadline Tracking Routing Engines

Reinstating an Administratively Dissolved Entity

This guide is part of the Penalty Avoidance & Grace-Period Mapping area within the Deadline Tracking & Routing Engines framework: it handles the terminal state, where the cure window has already closed and the entity has been administratively dissolved. Reinstatement is not one filing — it is a dependency-ordered sequence of them, and doing it in the wrong order gets steps rejected and money wasted. This guide plans and executes that sequence.

Scope of This Page

This page covers orchestrating the reinstatement path after administrative dissolution: identifying the delinquent back-filings, computing the back-fees and penalties, rechecking name availability, and submitting the reinstatement application in an order the registry will accept. It excludes everything before dissolution — computing whether the entity is still curable is Calculating Multi-State Grace Periods and Cure Windows, and reducing accrued penalties is Automating Penalty Waiver and Abatement Requests. Here the entity is already dissolved and we are rebuilding it to good standing.

The Constraint That Makes Ordering Non-Negotiable

Reinstatement fails when steps run in the wrong order, and the ordering is dictated by statute, not preference. A registry will not process a reinstatement application while delinquent annual reports remain unfiled, because reinstatement is conditioned on the entity being current — so back-filings must precede the application. It will not accept the application without the accompanying back-fees and penalties tendered, so the fee computation must precede submission. And it will not restore an entity under a name a competitor has claimed during the dissolution period, so a name-availability recheck may gate the whole plan. Delaware requires all delinquent franchise taxes, penalties, and interest paid and files a certificate of revival under 8 Del. C. § 502 with its § 510 interest; California requires the delinquent Statements of Information filed and FTB clearance before the Secretary of State will revive an entity suspended under Cal. Corp. Code § 2205; Texas requires the past-due franchise reports and payment plus a tax-clearance letter before reinstating a forfeited entity under Tex. Tax Code § 171 and BOC § 4.002; New York’s revival for tax dissolution runs through the Tax Department for consent before the Department of State restores the entity under N.Y. BCL § 408 and Tax Law § 203-a. Because each of these is a prerequisite edge, the correct representation is a dependency graph, and the correct executor walks it in topological order.

Prerequisites

  • Python 3.10+ — for graphlib.TopologicalSorter, match, and modern typing.
  • Standard library: graphlib, dataclasses, enum, logging, json, datetime. The dependency arithmetic needs nothing more.
  • A confirmed dissolution status from the live registry — verify via Good-Standing Certificate Automation before starting, so you do not reinstate an entity that was never actually dissolved.
  • A per-jurisdiction reinstatement recipe: the ordered prerequisites, the governing statute, and whether name recheck and tax clearance are required.

Implementation: A Dependency-Ordered Reinstatement Planner

The module below builds the reinstatement plan as a directed acyclic graph of steps, each with explicit prerequisites, and executes it in topological order. A step is attempted only once all its prerequisites report DONE; any failure halts descendants rather than submitting an application the registry will bounce. Every step transition is logged as a structured audit event. Comments mark the compliance-critical lines.

The reinstatement dependency graph: back-filings and name recheck gate the fee tender and application, which gate restored good standing A directed acyclic graph in which filing delinquent back-reports precedes computing back-fees, name recheck and tax clearance also gate the reinstatement application, and the application is the sole prerequisite of restored good standing; the executor walks it topologically and halts descendants on failure. Reinstatement as a dependency graph: no step begins until every prerequisite is done File delinquent back-reports Recheck name availability Compute + tender back-fees + penalties Obtain tax-clearance letter CA/TX/NY conditional Submit reinstatement application certificate of revival Restored good standing name clears → application Executor walks the graph in topological order · a step runs only when every prerequisite reports DONE any failure halts descendants → no application is submitted while a prerequisite is unmet
from __future__ import annotations

import json
import logging
from collections.abc import Callable
from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import Enum
from graphlib import CycleError, TopologicalSorter

logging.basicConfig(level=logging.INFO, format="%(message)s")
logger = logging.getLogger("compliance.reinstatement")


class StepState(str, Enum):
    PENDING = "pending"
    DONE = "done"
    FAILED = "failed"
    BLOCKED = "blocked"   # a prerequisite failed, so this step can never run


@dataclass
class Step:
    key: str
    label: str
    requires: frozenset[str]                 # keys that must be DONE first
    action: Callable[[], bool]               # returns True on success
    state: StepState = StepState.PENDING


@dataclass
class ReinstatementRecipe:
    """Per-jurisdiction ordering + statute; the recipe is data, not control flow."""
    jurisdiction: str
    statute: str
    needs_name_recheck: bool
    needs_tax_clearance: bool


RECIPES: dict[str, ReinstatementRecipe] = {
    "DE": ReinstatementRecipe("DE", "8 Del. C. §§ 502, 510", needs_name_recheck=True, needs_tax_clearance=False),
    "CA": ReinstatementRecipe("CA", "Cal. Corp. Code § 2205", needs_name_recheck=False, needs_tax_clearance=True),
    "TX": ReinstatementRecipe("TX", "Tex. BOC § 4.002; Tax Code § 171", needs_name_recheck=True, needs_tax_clearance=True),
    "NY": ReinstatementRecipe("NY", "N.Y. BCL § 408; Tax Law § 203-a", needs_name_recheck=False, needs_tax_clearance=True),
}


def build_plan(recipe: ReinstatementRecipe, actions: dict[str, Callable[[], bool]]) -> dict[str, Step]:
    """Assemble the dependency graph for one jurisdiction's reinstatement."""
    steps: dict[str, Step] = {}

    def add(key: str, label: str, requires: set[str]) -> None:
        steps[key] = Step(key, label, frozenset(requires), actions[key])

    add("back_reports", "File delinquent back-reports", set())
    # Fees cannot be computed final until the delinquent reports define what is owed.
    add("back_fees", "Compute and tender back-fees + penalties", {"back_reports"})
    app_requires = {"back_fees"}
    if recipe.needs_name_recheck:
        add("name_recheck", "Recheck name availability", set())
        app_requires.add("name_recheck")          # a lost name blocks the whole revival
    if recipe.needs_tax_clearance:
        add("tax_clearance", "Obtain tax-clearance letter", {"back_reports"})
        app_requires.add("tax_clearance")          # registry will not revive without clearance
    add("application", "Submit reinstatement application", app_requires)
    add("restored", "Restored good standing", {"application"})
    return steps


class ReinstatementExecutor:
    def __init__(self, jurisdiction: str, steps: dict[str, Step]) -> None:
        self._jur = jurisdiction
        self._steps = steps

    def _audit(self, step: Step) -> None:
        logger.info(json.dumps({
            "event": "reinstatement_step",
            "jurisdiction": self._jur,
            "step": step.key, "label": step.label, "state": step.state.value,
            "ts": datetime.now(timezone.utc).isoformat(),
        }))

    def run(self) -> bool:
        graph = {k: set(s.requires) for k, s in self._steps.items()}
        try:
            order = list(TopologicalSorter(graph).static_order())
        except CycleError as exc:                  # a mis-authored recipe must fail loudly
            logger.error(json.dumps({"event": "reinstatement_cycle", "detail": str(exc)}))
            raise

        for key in order:
            step = self._steps[key]
            # A step runs only if every prerequisite is DONE; otherwise it is BLOCKED.
            if any(self._steps[r].state is not StepState.DONE for r in step.requires):
                step.state = StepState.BLOCKED
                self._audit(step)
                continue
            step.state = StepState.DONE if step.action() else StepState.FAILED
            self._audit(step)
            if step.state is StepState.FAILED:
                logger.error(json.dumps({"event": "reinstatement_halt", "at": key}))
                return False
        return self._steps["restored"].state is StepState.DONE


if __name__ == "__main__":
    recipe = RECIPES["TX"]
    acts: dict[str, Callable[[], bool]] = {
        "back_reports": lambda: True,
        "back_fees": lambda: True,
        "name_recheck": lambda: True,
        "tax_clearance": lambda: True,
        "application": lambda: True,
        "restored": lambda: True,
    }
    plan = build_plan(recipe, acts)
    ok = ReinstatementExecutor("TX", plan).run()
    print("reinstated" if ok else "halted", "under", recipe.statute)

The executor’s guarantee is that it never submits the reinstatement application while any prerequisite is unmet: a failed back-filing leaves the application BLOCKED, not attempted. That is the whole point — the registry charges for a bounced application in wasted time and, in some states, non-refundable fees, so the ordering must be enforced before submission, not discovered after rejection.

DE / CA / NY / TX Reinstatement Requirements

Jurisdiction Statutory anchor Prerequisites before the application Ordering trap
Delaware 8 Del. C. §§ 502, 510 All delinquent franchise taxes, penalties, and 1.5%/mo interest paid; certificate of revival Interest keeps accruing until paid, so the fee figure is only final once tendered — compute it at submission, not from a stale quote.
California Cal. Corp. Code § 2205 Delinquent Statements of Information filed; FTB tax clearance before SOS revives Two agencies: the FTB clears the tax side and the Secretary of State revives — clearance must land before the revival request or it bounces.
New York N.Y. BCL § 408; Tax Law § 203-a Tax Department consent to reinstatement; back taxes resolved before DOS restores Consent is issued by the Tax Department, not the Department of State, so the dependency crosses agencies and cannot be parallelized.
Texas Tex. BOC § 4.002; Tax Code § 171 Past-due franchise reports filed and paid; tax-clearance letter from the Comptroller Forfeiture is two-stage (transaction rights, then charter); a name may need rechecking if the forfeiture period was long.

Failure Modes and Fallback Routing

Each fault maps onto the parent discipline’s error categorization & retry logic taxonomy.

  1. Application submitted before back-reports are filed (data-validation). The most expensive mistake, because a rejected reinstatement can forfeit non-refundable fees. The topological order makes application unreachable until back_reports and back_fees report DONE; a failure in either leaves the application BLOCKED, never attempted.
  2. Name claimed by a third party during dissolution (statutory). In a state that requires name_recheck, a lost name blocks revival entirely and forces a name change or a consent-to-use filing. Because the recheck is a prerequisite edge, the executor surfaces the blocker before spending fees on an application that cannot succeed under the old name.
  3. Tax-clearance letter delayed by a second agency (system). California and New York route clearance through a separate tax authority whose turnaround is outside your control. The step is modeled as its own node with back_reports as a prerequisite, so a pending clearance holds the application without failing the plan; the obligation stays visible to Priority Scoring Algorithms while it waits.
  4. A mis-authored recipe introduces a cycle (system). If a future edit makes two steps mutually dependent, TopologicalSorter raises CycleError at planning time rather than deadlocking at run time — a loud failure on a bad recipe is preferable to a silent hang mid-reinstatement.

Frequently Asked Questions

Why model reinstatement as a graph instead of a fixed checklist?

Because the steps are not independent and their order is dictated by statute: fees cannot be finalized until the delinquent reports define what is owed, and the application is rejected unless both the filings and the fees are already complete. A flat checklist lets a step run out of order; a dependency graph makes an out-of-order step structurally impossible, and the topological walk produces a correct order for any jurisdiction’s recipe without hand-sequencing.

Do I need to verify the entity is really dissolved before running this?

Yes — always. The grace-mapping resolver reports a presumptive dissolution from statutory offsets, but a registry’s operational timeline often lags, and some entities flagged as dissolved are still technically active. Confirm live status through Good-Standing Certificate Automation first; reinstating an entity that was never dissolved wastes fees and can create a confusing record.

Why does the fee step depend on the back-filings rather than running in parallel?

Because what is owed is a function of what was unfiled. Penalties and interest — Delaware’s 1.5% monthly under § 510, for instance — accrue against each delinquent period, so the final figure is not known until the delinquent reports are filed and the accrual is closed. Computing fees in parallel risks tendering a stale amount the registry rejects, so the graph makes back_fees a child of back_reports.