Skip to main content

Anti-pattern catalog — overview

The Architectural Type System for Verum maintains a canonical catalog of architectural defects, each registered as a refinement-level predicate the compiler checks. This page indexes the catalog and explains its structure. Each anti-pattern has its deep entry in one of the three band-specific pages.

The catalog itself — the closed enumeration of canonical anti-patterns — is the canonical source. The website mirrors the catalog exactly; adding a new pattern is the only way to extend the surface, and the docs follow the catalog, never the other way round.

The catalog is enumerableverum audit --arch-discharges prints every entry with its current verdict for the project at hand. The catalog is also append-only: a future Verum version may add patterns; existing patterns are never renumbered or removed.

1. The three bands

The thirty-two patterns split into three bands by what kind of architectural concern they address. The bands are documentary categories — they all share the same diagnostic infrastructure, the same RFC code format (ATS-V-AP-NNN), and the same audit pipeline.

BandRangeConcernPage
Capability / composition coreAP-001 .. AP-010Capability discipline, composition algebra, lifecycle ordering, foundation drift, register mixing, transaction / resource straddling, CVE-closure completenessclassical
Boundary / lifecycle / capability ontologyAP-011 .. AP-026Stratum admissibility, boundary invariants, wire encoding, authentication, deterministic-test discipline, linear / affine / relevant capability flavours, persistence and time-bound contracts, transitive lifecycle, declaration vs body drift, foundation-content alignmentontology
Modal-temporal architectural calculusAP-027 .. AP-032Temporal stability, counterfactual brittleness, refactoring adjunctions, universal-property uniqueness, evolution-trigger satisfiability, Yoneda observer-functor invariancemtac

The classical and ontology bands together cover what the ATS-V specification calls static-architecture defects — violations the compiler can decide without simulating time or counterfactuals. The MTAC band handles the modal-temporal surface (per spec §20–§23): time as a non-linear lattice, counterfactuals as paired decision swaps, refactorings as adjunctions, observers as Yoneda functors.

2. The catalog at a glance

CodeNameBandTriggered by
AP-001CapabilityEscalationcorebody uses capability not declared in requires
AP-002CapabilityLeakcorelinear / affine capability passed beyond its declared scope
AP-003DependencyCyclecorecomposes_with graph contains a cycle
AP-004TierMixingcoretier-N cog calls into tier-M without a bridge
AP-005FoundationDriftcorecomposing cogs with incompatible foundations and no bridge
AP-006RegisterMixingcoreproof / discharge mixes incompatible MSFS registers
AP-007TxStraddlingcoretransaction lives across an await boundary without scope
AP-008ResourceStraddlingcorelinear resource (file handle, db connection) outlives its scope
AP-009LifecycleRegressioncorecitation chain regresses to a strictly-lower lifecycle rank
AP-010CveIncompletecorestrict-mode cog with at least one missing CVE-closure axis
AP-011AbsoluteBoundaryAttemptontologycog declares MsfsStratum::LAbs (AFN-T α violation)
AP-012InvariantViolationontologydeclared BoundaryInvariant is not preserved by the boundary's traffic
AP-013DanglingMessageTypeontologymessage type declared without a wire encoding
AP-014UnauthenticatedCrossingontologyNetwork boundary without BoundaryInvariant::AuthenticatedFirst
AP-015DeterministicViolationontologyDST / replay test depends on non-deterministic primitives
AP-016CapabilityDuplicationontologyLinear capability used twice (multiplicity violation)
AP-017OrphanCapabilityontologyRelevant capability declared but never exercised
AP-018MissingHandoffontologycomposition capability not listed in composes_with
AP-019FoundationDowngradeontologystrong foundation passed through a weaker one without bridge
AP-020TimeBoundLeakageontologyTimeBound capability outlives its declared TTL
AP-021PersistenceMismatchontologyPersist capability for an operation that is not actually durable
AP-022CapabilityLaunderingontologymulti-hop privilege escalation through unmarked boundary
AP-023FoundationForgeryontologydeclared foundation contradicts the cited axiom corpus
AP-024TransitiveLifecycleRegressionontologytransitive [T] → … → [H] citation chain
AP-025DeclarationDriftontologydeclared @arch_module(...) shape diverges from inferred shape
AP-026FoundationContentMismatchontologycode body uses constructs from a foreign foundation
AP-027TemporalInconsistencymtacinvariant fails to hold across two sampled time-points
AP-028CounterfactualBrittlenessmtacverdict is fragile under counterfactual decision swap
AP-029MissedAdjointmtacrefactoring claimed without its inverse adjoint pair
AP-030UniversalPropertyViolationmtacuniversal-property uniqueness claim with no witness
AP-031PhantomEvolutionmtacdeclared evolution path passes through an unsatisfiable trigger
AP-032YonedaInequivalentRefactormtacrefactor changes the observer-functor (Yoneda inequivalent)

3. The anatomy of an anti-pattern

Each entry in the catalog is structured identically. The catalog is a refinement-type-level specification — every pattern is a predicate, every diagnostic is a counterexample.

┌─ AP-NNN — name ──────────────────────────────────────────────┐
│ │
│ Severity: error / warning / hint │
│ Band: core | ontology | mtac │
│ Phase: arch-check | post-arch | bundle │
│ Stable: yes (RFC-locked) │
│ │
│ Predicate: forall Shape s, DiagnosticContext ctx. │
│ P(s, ctx) → defect │
│ │
│ Diagnostic: [error template with span pointers] │
│ │
│ Remediation: [canonical fix recipe] │
│ │
│ Pin test: smallest synthetic Shape that reproduces │
│ │
└───────────────────────────────────────────────────────────────┘

Three properties are load-bearing:

  1. The RFC code is stable. AP-001 always means CapabilityEscalation, even if the prose explanation is rewritten. Tooling that consumes audit reports can rely on the code as a permanent identifier.
  2. The predicate is published. Every anti-pattern's predicate is part of the catalog's externally observable surface. There are no hidden patterns that fire without an entry in this table. The catalog's predicate is the canonical reference; the docs paraphrase it.
  3. The pin test exists. Every catalog entry has a regression-pin synthetic example. The audit gate would surface a false negative if the pattern stopped triggering on its pin — the pin protects the catalog against silent degradation.

4. Severity levels

Patterns trigger at one of three severity levels:

  • Error — the build fails. Most core and ontology patterns are errors when the cog is in strict mode. The compiler refuses to emit code.
  • Warning — the build proceeds but verum audit reports the pattern. Used for patterns that may have legitimate workarounds in soft mode (e.g., AP-001 CapabilityEscalation is a warning when strict = false, error in strict mode).
  • Hint — informational only; the pattern is a candidate, pending confirmation by additional context. Used for inference hints (e.g., "consider declaring this capability explicitly").

Severity is per-pattern × per-cog: many patterns escalate to error in strict: true and remain warnings in soft mode. The escalation is encoded in each check_* function's Severity selection. verum.toml allows project overrides via [ats_v.severity]:

[ats_v.severity]
ap_005_foundation_drift = "warning" # ← demote from error
ap_019_foundation_downgrade = "error" # ← always error

Some patterns cannot be demoted below "warning" — those that would compromise soundness if silenced (most ontology patterns that touch the trusted base, all MTAC patterns).

5. Phases

Patterns trigger in three phases of the build:

  • arch-check — during the architectural type-checking phase, cog-by-cog. Most core patterns fire here.
  • post-arch — after every cog has been arch-checked, walking the cross-cog graph. Transitive patterns (AP-024 TransitiveLifecycleRegression, AP-022 CapabilityLaundering) and corpus-level invariants fire here.
  • bundle — at audit time, when verum audit --bundle walks the entire project. MTAC patterns fire here, because they require the full project graph plus the temporal / counterfactual / observer samples as input (see DiagnosticContext::temporal_samples / counterfactual_pairs / yoneda_observer_diff).

A pattern's phase is fixed; the audit pipeline runs phases in order and aggregates verdicts.

6. Suppressions and exceptions

ATS-V provides a single, audit-visible suppression mechanism:

@arch_module(
requires: [...],
@suppress(AP_005_foundation_drift, "explicitly bridged via core.proof.bridges")
)
module my_app.cross_foundation_proof;

The @suppress attribute:

  • Names the specific RFC code (no wildcards).
  • Carries a mandatory rationale string. The rationale is preserved in the audit chronicle.
  • Does not hide the pattern from verum audit; the audit report shows suppressed patterns separately, with their rationale.

There is no global suppression flag. There is no #[allow(...)]. Architectural defects are always observable.

7. Catalog growth

The catalog is append-only:

  • New patterns may be added in any release. They take the next unused RFC code.
  • Existing patterns may have their prose rewritten or their diagnostic improved.
  • Existing patterns may be split into two more-precise patterns (the original code is preserved as a deprecated alias).
  • Existing patterns may be demoted in severity but never removed.
  • Existing patterns may be promoted from warning to error only in major releases, and only with a deprecation cycle.

This discipline gives downstream codebases a stable target. A build that passes verum audit --arch-discharges today will continue to pass under future versions, modulo strict opt-in patterns.

8. The audit gate

verum audit --arch-discharges runs the catalog and emits a structured JSON report:

{
"schema_version": 2,
"verum_version": "0.x.y",
"patterns": [
{
"code": "ATS-V-AP-001",
"name": "CapabilityEscalation",
"severity": "error",
"verdict": "ok",
"occurrences": []
},
{
"code": "ATS-V-AP-009",
"name": "LifecycleRegression",
"severity": "error",
"verdict": "violations",
"occurrences": [
{
"citing": "my_app.checkout",
"cited": "my_app.experimental.zk_proof",
"citing_lifecycle": "Theorem(\"v1.0\")",
"cited_lifecycle": "Hypothesis(Medium)",
"rank_diff": 4
}
]
}
],
"summary": {
"total_patterns": 32,
"ok": 31,
"violations": 1,
"suppressed": 0
}
}

The report is suitable for archival in audit chronicles. Schema version 2 is the current schema; older schema versions are preserved as adapters.

9. Default severity at a glance

A common question: "how many of the thirty-two are errors by default?" The default is encoded in each check_* function; many patterns escalate when Shape.strict == true. The summary below is the strict-mode picture:

SeverityCountPatterns
Error24AP-001..AP-009 (core), AP-011, AP-012, AP-014, AP-015, AP-016, AP-018, AP-019, AP-022, AP-023, AP-024, AP-025, AP-027, AP-028, AP-029, AP-031
Warning6AP-010 (CveIncomplete in soft mode), AP-013, AP-017, AP-020, AP-021, AP-026
Hint2AP-030 (UniversalPropertyViolation candidate), AP-032 (YonedaInequivalentRefactor candidate)

A clean default-mode build emits zero warnings; a clean strict-mode build also has zero hints. Many codebases adopt strict mode incrementally per cog (via @arch_module(strict: true)).

10. Verum-side surface

The 32-pattern catalog is exposed on the Verum side as a first-class enum in core.architecture.anti_patterns:

public type AntiPatternCode is
| CapabilityEscalation // AP-001
| CapabilityLeak // AP-002
// ... 30 more variants
| YonedaInequivalentRefactor; // AP-032

public fn anti_pattern_code_str(c: AntiPatternCode) -> Text // "ATS-V-AP-NNN"
public fn anti_pattern_name(c: AntiPatternCode) -> Text // "PascalCase"
public fn anti_pattern_full_roster() -> List<AntiPatternCode> // all 32
public fn anti_pattern_roster_size_invariant() -> Bool // pin: == 32

Verum cogs may iterate anti_pattern_full_roster() to build runtime walks (e.g. an in-process audit cog that records which patterns its codebase has cleared). The roster size is pinned by the cross-side test in crates/verum_kernel/tests/k_arch_v_alignment.rs — adding a 33rd code requires updating both the kernel-side AntiPatternCode::full_list() and the Verum-side roster in the same change-set.

Companion types:

public type Severity is | Error | Warning | Hint;
public fn severity_tag(s: Severity) -> Text;

public type AntiPatternViolation is {
code: AntiPatternCode,
severity: Severity,
summary: Text,
human_message: Text,
auto_fix_suggestion: Maybe<Text>,
};

public type DiagnosticContext is {
cog_name: Text,
parent_module: Maybe<Text>,
};

AntiPatternViolation carries the dual-audience payload — both human-readable text and machine-readable RFC code — surfaced by the ATS-V phase as a structured compiler diagnostic.

11. Implementation status

Every code in the canonical 32-pattern roster has a corresponding check_* function on the kernel side. The mapping is:

AP codeCheck functionLives in
AP-001check_capability_escalationarch_anti_pattern.rs
AP-002check_capability_leakarch_anti_pattern.rs
AP-003check_dependency_cyclearch_anti_pattern.rs
AP-004check_tier_mixingarch_anti_pattern.rs
AP-005check_foundation_driftarch_anti_pattern.rs
AP-006check_register_mixingarch_anti_pattern.rs
AP-007check_tx_straddlingarch_anti_pattern.rs
AP-008check_resource_straddlingarch_anti_pattern.rs
AP-009check_lifecycle_regressionarch_anti_pattern.rs
AP-010check_cve_incompletearch_anti_pattern.rs
AP-011check_stratum_admissiblearch_anti_pattern.rs
AP-012check_invariant_violationarch_anti_pattern.rs
AP-013check_dangling_message_typearch_anti_pattern.rs
AP-014check_unauthenticated_crossingarch_anti_pattern.rs
AP-015check_deterministic_violationarch_anti_pattern.rs
AP-016check_capability_duplicationarch_anti_pattern.rs
AP-017check_orphan_capabilityarch_anti_pattern.rs
AP-018check_missing_handoffarch_anti_pattern.rs
AP-019check_foundation_downgradearch_anti_pattern.rs
AP-020check_time_bound_leakagearch_anti_pattern.rs
AP-021check_persistence_mismatcharch_anti_pattern.rs
AP-022check_capability_launderingarch_anti_pattern.rs
AP-023check_foundation_forgeryarch_anti_pattern.rs
AP-024check_transitive_lifecycle_regressionarch_anti_pattern.rs
AP-025check_declaration_driftarch_anti_pattern.rs
AP-026check_foundation_content_mismatcharch_anti_pattern.rs
AP-027check_temporal_inconsistencyarch_anti_pattern.rs
AP-028check_counterfactual_brittlenessarch_anti_pattern.rs
AP-029check_missed_adjointarch_anti_pattern.rs
AP-030check_universal_property_violationarch_anti_pattern.rs
AP-031check_phantom_evolutionarch_anti_pattern.rs
AP-032check_yoneda_inequivalent_refactorarch_anti_pattern.rs

All 32 functions return Option<AntiPatternViolation>None means the predicate holds (no violation), Some(v) carries the structured diagnostic. check_all_anti_patterns walks every function and aggregates violations. The cross-side pin test in crates/verum_kernel/tests/k_arch_v_alignment.rs::pin_all_thirty_two_codes_have_check_function asserts every entry in this table has a matching pub fn check_* in the source — adding a 33rd code requires updating both the enum and the table in lockstep.

12. Red-team closure axioms

Beyond the 32 declarative patterns, the Verum-side cog core.architecture.anti_patterns declares four kernel-discharge axioms that close known attack vectors against the declarative surface:

  • kernel_arch_capability_ontology_check (closes AT-1) — registry validation for Capability.Custom { tag, schema }.
  • kernel_arch_theorem_cve_required (closes AT-2) — Lifecycle.Theorem(...) requires CVE-closure regardless of strict.
  • kernel_arch_yoneda_canonical_roster_complete (closes AT-3) — Yoneda verdicts demand the full canonical 5-roster.
  • kernel_arch_consumes_format_check (closes AT-5) — consumes field format enforcement.

See the red-team page for full attack-vector analysis.

13. Cross-references