Appendix C - 8. Blocking semantic lints

The Structure of Blocking semantic lints — its shape at a glance:

Each lint scans the source for its invariant and reports findings. A blocking lint fails the build; a scoped, reason-bearing suppression comment escapes a legitimate exception.

flowchart LR
  Src[/Source tree/] --> Lint[Semantic lint]
  Lint -->|violation| Fail([build blocked])
  Lint -->|clean| Pass([build proceeds])
  Noqa[/Scoped suppression/] -.->|reason-bearing escape| Lint

Accessible description: a semantic lint scans the source tree for its invariant. A violation blocks the build; a clean scan lets it proceed. A scoped, reason-bearing suppression comment escapes a legitimate exception on a single line.

Projected from the catalogue entry validation-and-conformance / Blocking semantic lints.

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

Intent

Intent — A fleet of blocking semantic lints over the tool's own source (banned APIs, silent-catch bans, Console.WriteLine-in-prod, typed-seam violations) that fail the build on domain-invariant violations the compiler and review can't catch.

Motivation

The codebase carries hundreds of structural invariants: no silent catch, no banned API in prod, every cross-boundary call through its seam. Code review cannot hold hundreds of invariants in a reviewer's head, and the compiler enforces none of them (a silent catch, a banned API, a raw Console.WriteLine all compile fine). The failure is structural drift that quietly reintroduces a defect class, and it recurs continuously as code is written.

One of these lints once turned on its author. A regex meant to scan source for a banned pattern backtracked catastrophically on a real input and hung the deploy gate — the checker that guards the fleet became the thing that stalled it. The sting was personal: the author's doctoral research was on this precise failure, regular-expression denial of service, the class where a crafted string drives an innocent-looking pattern into exponential work. Knowing the failure cold did not stop shipping it. That is the lesson the entry carries. The cure was not a better regex or a lint that flags the bad one; it was to delete the surface — reach for the parser, and let the whole class go. The mechanism is the fix; this instance is why the fix reads the way it does.

Applicability

Structure

The Structure diagram appears at the top of this page.

Sample Code

A semantic lint encodes a domain rule the compiler can't and scans for it. This one bans a silent except — a catch that neither logs, re-raises, nor carries a justifying comment — because a silently swallowed error turns a fail-loud bug into a fail-quiet one. A reason-bearing suppression comment escapes a deliberate swallow.

import ast, sys

def lint(path: str, source: str, lines: list[str]) -> list[str]:
    """Ban the silent swallow: an `except` body that only passes, with no logging,
    re-raise, or justifying comment. A swallowed error hides a real failure."""
    findings = []
    for node in ast.walk(ast.parse(source)):
        if isinstance(node, ast.ExceptHandler):
            body_is_pass = all(isinstance(s, ast.Pass) for s in node.body)
            line = lines[node.lineno - 1]
            if body_is_pass and "noqa: silent-catch" not in line:   # scoped escape
                findings.append(f"{path}:{node.lineno}: silent except — log, re-raise, or justify")
    return findings

if __name__ == "__main__":
    hits = []
    for p in sys.argv[1:]:
        text = open(p).read()
        hits += lint(p, text, text.splitlines())
    print("\n".join(hits)); sys.exit(1 if hits else 0)

Consequences

Example use within DocAble

Contents
© James C. Davis, 2026–present