Appendix C - 20. Typed `ViolationCategory` / `FailureCategory` enums

The Structure of Typed ViolationCategory / FailureCategory enums — its shape at a glance:

Producers and consumers speak the enum, not strings. External strings are mapped into the enum at one boundary. An exhaustiveness check lights up when a handler misses a case.

flowchart LR
  Ext[/External strings/] -->|map at boundary| Enum["Typed category enum"]
  Prod[Producers] --> Enum
  Enum --> Cons[Consumers / handlers]
  Cons --> X{{Exhaustiveness check}}
  X -.->|missing case| Fail([compile error])

Accessible description: external strings are mapped into a typed category enum at one boundary; producers and consumers speak the enum. An exhaustiveness check over the handlers produces a compile error when a case is unhandled.

Projected from the catalogue entry repair-vocabulary / Typed ViolationCategory / FailureCategory enums.

On this page: Intent · Motivation · Applicability · Structure · Sample Code · Consequences · Example use within DocAble · Related Patterns

Intent

Intent — Replace free-form failure strings with typed enums, so the categorical move-space is a closed, enumerable set that the compiler and lints can check for exhaustive handling.

Motivation

Bare failure strings ("timeout", "corrupt", "rate_limit") are typo-prone, un-enumerable, and let a switch silently miss a case. A typo compiles and mis-routes; a new category isn't forced into every handler; and you can't even ask "are all categories handled?" The failure is an unhandled or mistyped category → silent misbehaviour, recurring at every place a category is produced or consumed.

Applicability

Structure

The Structure diagram appears at the top of this page.

Sample Code

An enum turns an open string vocabulary into a closed, checkable set. Callers compare against enum members, not raw strings, so a typo is a name error at author time. External strings arrive at one boundary and map in; an unmapped string fails loudly there rather than silently mis-routing downstream.

from enum import Enum

class FailureCategory(Enum):
    TIMEOUT = "timeout"
    CORRUPT = "corrupt"
    RATE_LIMIT = "rate_limit"

_FROM_WIRE = {c.value: c for c in FailureCategory}

def parse_category(raw: str) -> FailureCategory:
    """The one boundary where external strings become the typed category.
    An unknown string fails here, loudly — not three layers down as a silent miss."""
    try:
        return _FROM_WIRE[raw]
    except KeyError:
        raise ValueError(f"unknown failure category {raw!r}")

def handle(cat: FailureCategory) -> str:
    # exhaustive match: adding a new enum member makes this branch incomplete,
    # which a type-checker flags — the missing case can't stay silent
    match cat:
        case FailureCategory.TIMEOUT:    return "retry"
        case FailureCategory.CORRUPT:    return "fail"
        case FailureCategory.RATE_LIMIT: return "backoff"

Consequences

Example use within DocAble

Contents
© James C. Davis, 2026–present