Defensive Theater
Defensive theater is code that looks robust, extensible, or production-safe but
does not actually improve behavior. Review these patterns carefully because they
can create false confidence without an obvious failing test.
Common Forms
- Optional imports that silently disable a required capability.
- Provider, strategy, plugin, or registry abstractions with one implementation
and no demonstrated substitution point.
- Broad
try/except or try/catch wrappers that hide initialization,
network, persistence, or schema failures.
- Compatibility layers that return defaults instead of preserving unsupported
behavior as an explicit error.
- Capability flags, health checks, or status endpoints that are never connected
to real dependencies.
- Resilience wrappers such as retries, circuit breakers, timeouts, queues, or
caches that do not affect the failing operation.
What Makes It A Finding
Report defensive theater when the code:
- claims support for a capability that is absent, unreachable, or untested
- hides a failure that callers or operators need to see
- creates a misleading abstraction boundary that future code will rely on
- bypasses an existing architecture rule under the appearance of compatibility
- adds operational signals that cannot detect the real failure mode
The issue is not that the code is defensive. The issue is that the defense is
non-semantic: it changes perception more than behavior.
Legitimate Patterns
Do not flag these without additional evidence:
- Optional dependency support that clearly reports degraded mode and preserves
documented semantics.
- A provider interface required by an existing framework, package boundary, or
near-term second implementation already present in the change.
- Error handling that narrows known recoverable failures while preserving
unexpected failures.
- Compatibility shims with tests for both old and new behavior.
- Health checks that intentionally measure only process liveness and are named
that way.
Review Questions
Ask:
- What guarantee does this defensive code appear to provide?
- Which exact failure mode is it supposed to handle?
- Does it preserve semantics for callers, or only avoid crashing?
- Is degraded mode observable through return values, logs, metrics, traces, or
audit records?
- Is the abstraction substitutable today, or is it speculative complexity?
If the answer is mostly "it makes the code look safer", treat it as a lead. If
the answer identifies a real recoverable failure with preserved semantics and
tests, do not report it.
Remediation Guidance
Useful fixes are concrete:
- fail closed or return an explicit unsupported/degraded status
- remove unused abstraction until a second implementation exists
- add contract tests for each provider/fallback path
- connect health/capability checks to the dependency they claim to cover
- preserve and surface root-cause errors where operators need them